implement valid week string

This commit is contained in:
tigercosmos 2017-12-14 21:23:06 +08:00
parent b93579a8f0
commit 54c6028033
11 changed files with 103 additions and 128 deletions

22
Cargo.lock generated
View file

@ -358,6 +358,15 @@ dependencies = [
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clang-sys"
version = "0.21.1"
@ -2044,6 +2053,16 @@ dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.34"
@ -2538,6 +2557,7 @@ dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1",
"caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3776,6 +3796,7 @@ dependencies = [
"checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86765cb42c2a2c497e142af72517c1b4d7ae5bb2f25dfa77a5c69642f2342d89"
"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9"
"checksum clang-sys 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00048189ee171715296dfe3b2fcfd439563c7bfec0d98d3976ce3402d62c8f07"
"checksum clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc34bf7d5d66268b466b9852bca925ec1d2650654dab4da081e63fd230145c2e"
"checksum clipboard 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd3a9a938558f33ec1baaa6ca631a69c104aafaacbc66868d9ad28cf5f30564f"
@ -3895,6 +3916,7 @@ dependencies = [
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40"
"checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37"
"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e"
"checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44"

View file

@ -39,6 +39,7 @@ byteorder = "1.0"
canvas_traits = {path = "../canvas_traits"}
caseless = "0.1.0"
cookie = "0.10"
chrono = "0.4"
cssparser = "0.23.0"
deny_public_fields = {path = "../deny_public_fields"}
devtools_traits = {path = "../devtools_traits"}

View file

@ -4,6 +4,8 @@
//! The `ByteString` struct.
use chrono::{Datelike, TimeZone};
use chrono::prelude::{Weekday, Utc};
use cssparser::CowRcStr;
use html5ever::{LocalName, Namespace};
use servo_atoms::Atom;
@ -293,6 +295,13 @@ impl DOMString {
pub fn is_valid_month_string(&self) -> bool {
parse_month_string(&*self.0).is_ok()
}
/// 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
/// https://html.spec.whatwg.org/multipage/#valid-week-string
pub fn is_valid_week_string(&self) -> bool {
parse_week_string(&*self.0).is_ok()
}
}
impl Borrow<str> for DOMString {
@ -445,6 +454,48 @@ fn parse_date_string(value: &str) -> Result<(u32, u32, u32), ()> {
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
fn parse_month_component(value: &str) -> Result<(u32, u32), ()> {
// Step 3
@ -495,7 +546,7 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
1|3|5|7|8|10|12 => Ok(31),
4|6|9|11 => Ok(30),
2 => {
if year_num % 400 == 0 || (year_num % 4 == 0 && year_num % 100 != 0) {
if is_leap_year(year_num) {
Ok(29)
} else {
Ok(28)
@ -504,3 +555,17 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
_ => Err(())
}
}
// https://html.spec.whatwg.org/multipage/#week-number-of-the-last-day
fn max_week_in_year(year: u32) -> u32 {
match Utc.ymd(year as i32, 1, 1).weekday() {
Weekday::Thu => 53,
Weekday::Wed if is_leap_year(year) => 53,
_ => 52
}
}
#[inline]
fn is_leap_year(year: u32) -> bool {
year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
}

View file

@ -1005,6 +1005,12 @@ impl HTMLInputElement {
*textinput.single_line_content_mut() = "".into();
}
}
InputType::Week => {
let mut textinput = self.textinput.borrow_mut();
if !textinput.single_line_content().is_valid_week_string() {
*textinput.single_line_content_mut() = "".into();
}
}
InputType::Color => {
let mut textinput = self.textinput.borrow_mut();

View file

@ -31,6 +31,7 @@ extern crate bluetooth_traits;
extern crate byteorder;
extern crate canvas_traits;
extern crate caseless;
extern crate chrono;
extern crate cookie as cookie_rs;
#[macro_use] extern crate cssparser;
#[macro_use] extern crate deny_public_fields;

View file

@ -29,7 +29,9 @@ rand = [
"uuid",
"ws",
]
num = []
num = [
"chrono",
]
[ignore]
# Ignored packages with duplicated versions

View file

@ -543087,7 +543087,7 @@
"testharness"
],
"html/semantics/forms/the-input-element/week.html": [
"851b1b794f820b1fb9b7ee57fe39f8f2977b7fe6",
"95fa0e8176311adcbb5a8d0d408d3c4c8bea100c",
"testharness"
],
"html/semantics/forms/the-label-element/.gitkeep": [

View file

@ -6,9 +6,6 @@
[change state from hidden to datetime]
expected: FAIL
[change state from hidden to week]
expected: FAIL
[change state from hidden to number]
expected: FAIL
@ -21,9 +18,6 @@
[change state from text to datetime]
expected: FAIL
[change state from text to week]
expected: FAIL
[change state from text to number]
expected: FAIL
@ -36,9 +30,6 @@
[change state from search to datetime]
expected: FAIL
[change state from search to week]
expected: FAIL
[change state from search to number]
expected: FAIL
@ -51,9 +42,6 @@
[change state from tel to datetime]
expected: FAIL
[change state from tel to week]
expected: FAIL
[change state from tel to number]
expected: FAIL
@ -75,9 +63,6 @@
[change state from url to datetime]
expected: FAIL
[change state from url to week]
expected: FAIL
[change state from url to number]
expected: FAIL
@ -108,9 +93,6 @@
[change state from email to datetime]
expected: FAIL
[change state from email to week]
expected: FAIL
[change state from email to number]
expected: FAIL
@ -123,9 +105,6 @@
[change state from password to datetime]
expected: FAIL
[change state from password to week]
expected: FAIL
[change state from password to number]
expected: FAIL
@ -171,27 +150,9 @@
[change state from month to range]
expected: FAIL
[change state from week to reset]
expected: FAIL
[change state from week to button]
expected: FAIL
[change state from week to email]
expected: FAIL
[change state from week to datetime]
expected: FAIL
[change state from week to number]
expected: FAIL
[change state from week to hidden]
expected: FAIL
[change state from week to number]
expected: FAIL
[change state from week to range]
expected: FAIL
@ -228,9 +189,6 @@
[change state from number to datetime]
expected: FAIL
[change state from number to week]
expected: FAIL
[change state from number to range]
expected: FAIL
@ -261,9 +219,6 @@
[change state from range to datetime]
expected: FAIL
[change state from range to week]
expected: FAIL
[change state from range to number]
expected: FAIL
@ -273,9 +228,6 @@
[change state from checkbox to datetime]
expected: FAIL
[change state from checkbox to week]
expected: FAIL
[change state from checkbox to number]
expected: FAIL
@ -288,9 +240,6 @@
[change state from radio to datetime]
expected: FAIL
[change state from radio to week]
expected: FAIL
[change state from radio to number]
expected: FAIL
@ -303,9 +252,6 @@
[change state from submit to datetime]
expected: FAIL
[change state from submit to week]
expected: FAIL
[change state from submit to number]
expected: FAIL
@ -318,9 +264,6 @@
[change state from image to datetime]
expected: FAIL
[change state from image to week]
expected: FAIL
[change state from image to number]
expected: FAIL
@ -333,9 +276,6 @@
[change state from reset to datetime]
expected: FAIL
[change state from reset to week]
expected: FAIL
[change state from reset to number]
expected: FAIL
@ -348,9 +288,6 @@
[change state from button to datetime]
expected: FAIL
[change state from button to week]
expected: FAIL
[change state from button to number]
expected: FAIL
@ -402,18 +339,12 @@
[change state from datetime-local to email]
expected: FAIL
[change state from datetime-local to week]
expected: FAIL
[change state from datetime-local to number]
expected: FAIL
[change state from datetime-local to range]
expected: FAIL
[change state from week to datetime-local]
expected: FAIL
[change state from number to datetime-local]
expected: FAIL
@ -453,33 +384,6 @@
[change state from datetime-local to password]
expected: FAIL
[change state from week to text]
expected: FAIL
[change state from week to search]
expected: FAIL
[change state from week to tel]
expected: FAIL
[change state from week to url]
expected: FAIL
[change state from week to password]
expected: FAIL
[change state from week to checkbox]
expected: FAIL
[change state from week to radio]
expected: FAIL
[change state from week to submit]
expected: FAIL
[change state from week to image]
expected: FAIL
[change state from number to text]
expected: FAIL
@ -513,9 +417,6 @@
[change state from color to datetime-local]
expected: FAIL
[change state from color to week]
expected: FAIL
[change state from color to number]
expected: FAIL

View file

@ -6,12 +6,6 @@
[value IDL attribute of input type datetime with value attribute]
expected: FAIL
[value IDL attribute of input type week without value attribute]
expected: FAIL
[value IDL attribute of input type week with value attribute]
expected: FAIL
[value IDL attribute of input type number without value attribute]
expected: FAIL

View file

@ -1,20 +0,0 @@
[week.html]
type: testharness
[2014 has 52 weeks: Value should be empty]
expected: FAIL
[Invalid value: year only]
expected: FAIL
[Invalid value: no week number]
expected: FAIL
[Invalid value: no '-' (U+002D)]
expected: FAIL
[Invalid value: yearless week]
expected: FAIL
[Invalid value: yearless week and no '-' (U+002D)]
expected: FAIL

View file

@ -17,6 +17,9 @@
{value: "2014W", expected: "", testname: "Invalid value: no week number"},
{value: "2014W52", expected: "", testname: "Invalid value: no '-' (U+002D)"},
{value: "-W52", expected: "", testname: "Invalid value: yearless week"},
{value: "2017-w52", expected: "", testname: "Invalid value: should be capital letter 'W'"},
{value: "2017-W52-", expected: "", testname: "Invalid value: incorrect with '-' at the end"},
{value: "2017-W52-12", expected: "", testname: "Invalid value: value should be two parts"},
{value: "W52", expected: "", testname: "Invalid value: yearless week and no '-' (U+002D)"},
{value: "2014-W03", attributes: { min: "2014-W02" }, expected: "2014-W03", testname: "Value >= min attribute"},
{value: "2014-W01", attributes: { min: "2014-W02" }, expected: "2014-W01", testname: "Value < min attribute"},