diff options
author | tigercosmos <phy.tiger@gmail.com> | 2017-12-14 21:23:06 +0800 |
---|---|---|
committer | tigercosmos <phy.tiger@gmail.com> | 2017-12-17 16:57:01 +0800 |
commit | 54c6028033d07d9104f58beb3d92bcc819600d93 (patch) | |
tree | eecab9c0387eb4cc46ba45b4b893401b262a7609 /components | |
parent | b93579a8f0e59c8102a243133455d8012e82e415 (diff) | |
download | servo-54c6028033d07d9104f58beb3d92bcc819600d93.tar.gz servo-54c6028033d07d9104f58beb3d92bcc819600d93.zip |
implement valid week string
Diffstat (limited to 'components')
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/str.rs | 67 | ||||
-rwxr-xr-x | components/script/dom/htmlinputelement.rs | 6 | ||||
-rw-r--r-- | components/script/lib.rs | 1 |
4 files changed, 74 insertions, 1 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 5561cd7dd95..8c3c77ed27c 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -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"} diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs index 596b2db14b2..83c438a26e7 100644 --- a/components/script/dom/bindings/str.rs +++ b/components/script/dom/bindings/str.rs @@ -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) +} diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index a951c49f80c..8c5699446ef 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -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(); diff --git a/components/script/lib.rs b/components/script/lib.rs index 3bae98a1a06..3143342e4f6 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -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; |