Auto merge of #19379 - SWW13:htmlinput_sanitize_time, r=KiChjang

Implemented sanitize_value for time input

Implemented value sanitization for `<input type=time/>`.
The value has the be valid time string (https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-time-string) or set to empty string.

---

The following test results look expected to me, but I'm not sure:
```
  ▶ Unexpected subtest result in /html/semantics/forms/the-input-element/type-change-state.html:
  │ FAIL [expected PASS] change state from time to text
  │   → assert_equals: input.value should be   foobar   after change of state expected "  foobar  " but got ""
  │ FAIL [expected PASS] change state from time to search
  │   → assert_equals: input.value should be   foobar   after change of state expected "  foobar  " but got ""
  │ FAIL [expected PASS] change state from time to tel
  │   → assert_equals: input.value should be   foobar   after change of state expected "  foobar  " but got ""
  │ FAIL [expected PASS] change state from time to url
  │   → assert_equals: input.value should be foobar after change of state expected "foobar" but got ""
  │ FAIL [expected PASS] change state from time to password
  │   → assert_equals: input.value should be   foobar   after change of state expected "  foobar  " but got ""
  │
  │ @http://web-platform.test:8000/html/semantics/forms/the-input-element/type-change-state.html:53:15
  │ Test.prototype.step@http://web-platform.test:8000/resources/testharness.js:1489:20
  │ test@http://web-platform.test:8000/resources/testharness.js:511:9
  └ @http://web-platform.test:8000/html/semantics/forms/the-input-element/type-change-state.html:37:9

  ▶ Unexpected subtest result in /html/semantics/forms/the-input-element/type-change-state.html:
  │ FAIL [expected PASS] change state from color to time
  │   → assert_equals: input.value should be #000000 after change of state expected "#000000" but got ""
  │
  │ @http://web-platform.test:8000/html/semantics/forms/the-input-element/type-change-state.html:55:15
  │ Test.prototype.step@http://web-platform.test:8000/resources/testharness.js:1489:20
  │ test@http://web-platform.test:8000/resources/testharness.js:511:9
  └ @http://web-platform.test:8000/html/semantics/forms/the-input-element/type-change-state.html:37:9
```

All other tests do now `PASS` instead of `FAIL`.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix *part of* #19172
- [x] There are tests for these changes
  - [x] All tests `PASS`

<!-- 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/19379)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-12-04 15:44:58 -06:00 committed by GitHub
commit eed3adc957
8 changed files with 228 additions and 157 deletions

View file

@ -208,6 +208,77 @@ impl DOMString {
self.0.truncate(last_non_whitespace);
let _ = self.0.splice(0..first_non_whitespace, "");
}
/// Validates this `DOMString` is a time string according to
/// <https://html.spec.whatwg.org/multipage/#valid-time-string>.
pub fn is_valid_time_string(&self) -> bool {
enum State {
HourHigh,
HourLow09,
HourLow03,
MinuteColon,
MinuteHigh,
MinuteLow,
SecondColon,
SecondHigh,
SecondLow,
MilliStop,
MilliHigh,
MilliMiddle,
MilliLow,
Done,
Error,
}
let next_state = |valid: bool, next: State| -> State { if valid { next } else { State::Error } };
let state = self.chars().fold(State::HourHigh, |state, c| {
match state {
// Step 1 "HH"
State::HourHigh => {
match c {
'0' | '1' => State::HourLow09,
'2' => State::HourLow03,
_ => State::Error,
}
},
State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon),
State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon),
// Step 2 ":"
State::MinuteColon => next_state(c == ':', State::MinuteHigh),
// Step 3 "mm"
State::MinuteHigh => next_state(c.is_digit(6), State::MinuteLow),
State::MinuteLow => next_state(c.is_digit(10), State::SecondColon),
// Step 4.1 ":"
State::SecondColon => next_state(c == ':', State::SecondHigh),
// Step 4.2 "ss"
State::SecondHigh => next_state(c.is_digit(6), State::SecondLow),
State::SecondLow => next_state(c.is_digit(10), State::MilliStop),
// Step 4.3.1 "."
State::MilliStop => next_state(c == '.', State::MilliHigh),
// Step 4.3.2 "SSS"
State::MilliHigh => next_state(c.is_digit(6), State::MilliMiddle),
State::MilliMiddle => next_state(c.is_digit(10), State::MilliLow),
State::MilliLow => next_state(c.is_digit(10), State::Done),
_ => State::Error,
}
});
match state {
State::Done |
// Step 4 (optional)
State::SecondColon |
// Step 4.3 (optional)
State::MilliStop |
// Step 4.3.2 (only 1 digit required)
State::MilliMiddle | State::MilliLow => true,
_ => false
}
}
}
impl Borrow<str> for DOMString {

View file

@ -895,6 +895,13 @@ impl HTMLInputElement {
textinput.set_content("#000000".into());
}
}
atom!("time") => {
let mut textinput = self.textinput.borrow_mut();
if ! textinput.single_line_content().is_valid_time_string() {
*textinput.single_line_content_mut() = "".into();
}
}
// TODO: Implement more value sanitization algorithms for different types of inputs
_ => ()
}