diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index c8f7e63358ec..28f67bf5af68 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -166,6 +166,8 @@ where // Step 8.4 element.set_custom_element_definition(definition.clone()); + element.done_creating(); + // Step 8.5 DomRoot::downcast(element).ok_or(Error::InvalidState) }, diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 4144bb972ca3..f56836769d93 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -14,6 +14,7 @@ use dom::bindings::codegen::Bindings::ElementBinding; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::FunctionBinding::Function; +use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; @@ -159,6 +160,7 @@ pub struct Element { custom_element_definition: DomRefCell>>, /// custom_element_state: Cell, + done_creating: Cell, } impl fmt::Debug for Element { @@ -243,6 +245,18 @@ impl Element { document: &Document, creator: ElementCreator, mode: CustomElementCreationMode, + ) -> DomRoot { + let el = Element::create_unfinished(name, is, document, creator, mode); + el.done_creating(); + el + } + + pub fn create_unfinished( + name: QualName, + is: Option, + document: &Document, + creator: ElementCreator, + mode: CustomElementCreationMode, ) -> DomRoot { create_element(name, is, document, creator, mode) } @@ -286,9 +300,21 @@ impl Element { custom_element_reaction_queue: Default::default(), custom_element_definition: Default::default(), custom_element_state: Cell::new(CustomElementState::Uncustomized), + done_creating: Cell::new(false), + } + } + + pub fn done_creating(&self) { + self.done_creating.set(true); + if let Some(el) = self.downcast::() { + el.refresh_value(el.Value()); } } + pub fn is_done_creating(&self) -> bool { + self.done_creating.get() + } + pub fn new( local_name: LocalName, namespace: Namespace, diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 163a85cbdb68..7adcc8509c39 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -1122,8 +1122,18 @@ impl HTMLInputElement { } } + pub fn refresh_value(&self, mut value: DOMString) { + let mut textinput = self.textinput.borrow_mut(); + self.sanitize_value(&mut value); + textinput.set_content(value); + } + // https://html.spec.whatwg.org/multipage/#value-sanitization-algorithm fn sanitize_value(&self, value: &mut DOMString) { + let el = self.upcast::(); + if !el.is_done_creating() { + return + } match self.input_type() { InputType::Text | InputType::Search | InputType::Tel | InputType::Password => { value.strip_newlines(); @@ -1183,7 +1193,47 @@ impl HTMLInputElement { }, // https://html.spec.whatwg.org/multipage/#range-state-(type=range):value-sanitization-algorithm InputType::Range => { - value.set_best_representation_of_the_floating_point_number(); + let minimum = self.Min().parse().unwrap_or(0f64); + let maximum = self.Max().parse().unwrap_or(100f64); + + let new_v = if let Ok(value) = value.trim().parse::() { + if value < minimum || maximum < minimum { + minimum + } else if value > maximum { + maximum + } else { + value + } + } else { + if maximum <= minimum { + minimum + } else { + minimum + (maximum - minimum) / 2f64 + } + }; + + let step = self.Step().parse::().unwrap_or(1f64); + let delta = (new_v - minimum) - step * ((new_v - minimum) / step).floor(); + let new_v = if delta != 0f64 { + let step_below = new_v - delta; + let step_above = new_v - delta + step; + let half_step = step / 2f64; + let step_above_is_closest = (step_above - new_v) <= half_step; + let step_above_in_range = step_above >= minimum && step_above <= maximum; + let step_below_in_range = step_below >= minimum && step_below <= maximum; + + if (step_above_is_closest || !step_below_in_range) && step_above_in_range { + step_above + } else if (!step_above_is_closest || !step_above_in_range) && step_below_in_range { + step_below + } else { + new_v + } + } else { + new_v + }; + + *value = DOMString::from_string(new_v.to_string()); }, _ => (), } @@ -1334,6 +1384,12 @@ impl VirtualMethods for HTMLInputElement { self.textinput.borrow_mut().set_content(value); self.update_placeholder_shown_state(); }, + &local_name!("max") | &local_name!("min") | &local_name!("step") => { + let mut textinput = self.textinput.borrow_mut(); + let mut value = textinput.single_line_content().clone(); + self.sanitize_value(&mut value); + textinput.set_content(value); + }, &local_name!("name") if self.input_type() == InputType::Radio => { self.radio_group_updated( mutation.new_value(attr).as_ref().map(|name| name.as_atom()), diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index e64580f68c1c..e0794dd154bb 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -1120,13 +1120,15 @@ fn create_element_for_token( } else { CustomElementCreationMode::Asynchronous }; - let element = Element::create(name, is, document, creator, creation_mode); + let element = Element::create_unfinished(name, is, document, creator, creation_mode); // Step 8. for attr in attrs { element.set_attribute_from_parser(attr.name, attr.value, None); } + element.done_creating(); + // Step 9. if will_execute_script { // Steps 9.1 - 9.2. diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 0c8f83804595..4f0c58aa1849 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -615929,7 +615929,7 @@ "testharness" ], "html/semantics/forms/the-input-element/range.html": [ - "209ce25306e02986238ae26fb6fdf38b0a26a500", + "f57c520b87ea8adceb7311ef8d642db5cc5fa6b8", "testharness" ], "html/semantics/forms/the-input-element/required_attribute.html": [ diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini deleted file mode 100644 index 13c7333bf957..000000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini +++ /dev/null @@ -1,14 +0,0 @@ -[range-2.html] - 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] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini index 4cecdb935bbd..29ffed47e1e5 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini @@ -1,35 +1,11 @@ [range.html] 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] expected: FAIL - [Solving the step mismatch] - expected: FAIL - [Performing stepUp()] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini index b4e046a284f3..6461455ff4a9 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini @@ -6,36 +6,24 @@ [change state from hidden to datetime] expected: FAIL - [change state from hidden to range] - expected: FAIL - [change state from text to email] expected: FAIL [change state from text to datetime] expected: FAIL - [change state from text to range] - expected: FAIL - [change state from search to email] expected: FAIL [change state from search to datetime] expected: FAIL - [change state from search to range] - expected: FAIL - [change state from tel to email] expected: FAIL [change state from tel to datetime] expected: FAIL - [change state from tel to range] - expected: FAIL - [change state from url to text] expected: FAIL @@ -51,9 +39,6 @@ [change state from url to datetime] expected: FAIL - [change state from url to range] - expected: FAIL - [change state from email to hidden] expected: FAIL @@ -78,18 +63,12 @@ [change state from email to datetime] expected: FAIL - [change state from email to range] - expected: FAIL - [change state from password to email] 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 @@ -117,126 +96,48 @@ [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 hidden] - expected: FAIL - - [change state from range to checkbox] - expected: FAIL - - [change state from range to radio] - expected: FAIL - - [change state from range to submit] - expected: FAIL - - [change state from range to image] - expected: FAIL - - [change state from range to reset] - expected: FAIL - - [change state from range to button] - expected: FAIL - - [change state from range to email] - expected: FAIL - [change state from range to datetime] expected: FAIL [change state from checkbox to email] expected: FAIL - [change state from checkbox to range] - expected: FAIL - [change state from radio to email] expected: FAIL [change state from radio to datetime] expected: FAIL - [change state from radio to range] - expected: FAIL - [change state from submit to email] expected: FAIL [change state from submit to datetime] expected: FAIL - [change state from submit to range] - expected: FAIL - [change state from image to email] expected: FAIL [change state from image to datetime] expected: FAIL - [change state from image to range] - expected: FAIL - [change state from reset to email] expected: FAIL [change state from reset to datetime] expected: FAIL - [change state from reset to range] - expected: FAIL - [change state from button to email] 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 range to text] - expected: FAIL - - [change state from range to search] - expected: FAIL - - [change state from range to tel] - expected: FAIL - - [change state from range to url] - expected: FAIL - - [change state from range to password] - expected: FAIL - - [change state from color to range] + [change state from range to number] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini index 7577868bb52f..132a45463209 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini @@ -6,12 +6,6 @@ [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 - [value IDL attribute of input type email without value attribute] expected: FAIL diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/range.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/range.html index 209ce25306e0..f57c520b87ea 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/range.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/range.html @@ -34,7 +34,7 @@

Input Range

- + @@ -286,7 +286,7 @@

Input Range

test( function() { var e = document.getElementById('should_skip_whitespace'); - assert_equals(e.value, "123") + assert_equals(e.value, "98") }, "Skip ASCII whitespace within input", { "help" : "https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number" }