Auto merge of #19559 - tigercosmos:t1, r=KiChjang

implement valid week string

<!-- Please describe your changes on the following line: -->
implement valid week string
part of #19172

r? @KiChjang

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [x] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19559)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-12-17 03:50:33 -06:00 committed by GitHub
commit 8798e49889
11 changed files with 103 additions and 128 deletions

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;