New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement range input sanitization #21952
Changes from all commits
File filter...
Jump to…
| @@ -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<Option<Rc<CustomElementDefinition>>>, | ||
| /// <https://dom.spec.whatwg.org/#concept-element-custom-element-state> | ||
| custom_element_state: Cell<CustomElementState>, | ||
| done_creating: Cell<bool>, | ||
| } | ||
|
|
||
| impl fmt::Debug for Element { | ||
| @@ -243,6 +245,18 @@ impl Element { | ||
| document: &Document, | ||
| creator: ElementCreator, | ||
| mode: CustomElementCreationMode, | ||
| ) -> DomRoot<Element> { | ||
| let el = Element::create_unfinished(name, is, document, creator, mode); | ||
| el.done_creating(); | ||
| el | ||
| } | ||
|
|
||
| pub fn create_unfinished( | ||
| name: QualName, | ||
| is: Option<LocalName>, | ||
| document: &Document, | ||
| creator: ElementCreator, | ||
| mode: CustomElementCreationMode, | ||
| ) -> DomRoot<Element> { | ||
| 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::<HTMLInputElement>() { | ||
| el.refresh_value(el.Value()); | ||
nox
Member
|
||
| } | ||
| } | ||
|
|
||
| pub fn is_done_creating(&self) -> bool { | ||
| self.done_creating.get() | ||
| } | ||
|
|
||
| pub fn new( | ||
| local_name: LocalName, | ||
| namespace: Namespace, | ||
| @@ -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::<Element>(); | ||
|
||
| 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); | ||
nox
Member
|
||
| let maximum = self.Max().parse().unwrap_or(100f64); | ||
|
|
||
| let new_v = if let Ok(value) = value.trim().parse::<f64>() { | ||
| if value < minimum || maximum < minimum { | ||
| minimum | ||
| } else if value > maximum { | ||
| maximum | ||
| } else { | ||
| value | ||
| } | ||
nox
Member
|
||
| } else { | ||
| if maximum <= minimum { | ||
|
||
| minimum | ||
| } else { | ||
| minimum + (maximum - minimum) / 2f64 | ||
| } | ||
| }; | ||
|
|
||
| let step = self.Step().parse::<f64>().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()), | ||
| @@ -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(); | ||
Eijebong
Author
Member
|
||
|
|
||
| // Step 9. | ||
| if will_execute_script { | ||
| // Steps 9.1 - 9.2. | ||
| "testharness" | ||
| ], | ||
| "html/semantics/forms/the-input-element/range.html": [ | ||
| "209ce25306e02986238ae26fb6fdf38b0a26a500", | ||
| "f57c520b87ea8adceb7311ef8d642db5cc5fa6b8", | ||
| "testharness" | ||
| ], | ||
| "html/semantics/forms/the-input-element/required_attribute.html": [ |
This file was deleted.
This seems to have become substeps of step 9, could you renumber the steps and add a todo for the now missing part?