diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-12-13 03:31:52 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-13 03:31:52 -0800 |
commit | a15d279e9f9eccc3d2e2cca6d1e0949e51732a63 (patch) | |
tree | 5c4b1e40453cede7fd9030e0020701c9e4612c88 | |
parent | a6cfec972f033df77276d74f7bc455f6717ea50f (diff) | |
parent | 51f9671db2c6ccb4e8627b2340d33d8020f457b5 (diff) | |
download | servo-a15d279e9f9eccc3d2e2cca6d1e0949e51732a63.tar.gz servo-a15d279e9f9eccc3d2e2cca6d1e0949e51732a63.zip |
Auto merge of #14085 - frewsxcv:list-of-options, r=asajeffrey
Implement "list of options" concept on `HTMLSelectElement`.
Fixes #13763.
<!-- 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/14085)
<!-- Reviewable:end -->
-rwxr-xr-x | components/script/dom/htmlselectelement.rs | 65 | ||||
-rw-r--r-- | tests/wpt/metadata/MANIFEST.json | 6 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/select-value.html | 56 |
3 files changed, 107 insertions, 20 deletions
diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 7f27a311e3d..25977da8095 100755 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -31,6 +31,7 @@ use dom::validation::Validatable; use dom::validitystate::{ValidityState, ValidationFlags}; use dom::virtualmethods::VirtualMethods; use html5ever_atoms::LocalName; +use std::iter; use style::attr::AttrValue; use style::element_state::*; @@ -84,10 +85,25 @@ impl HTMLSelectElement { HTMLSelectElementBinding::Wrap) } + // https://html.spec.whatwg.org/multipage/#concept-select-option-list + fn list_of_options(&self) -> impl Iterator<Item=Root<HTMLOptionElement>> { + self.upcast::<Node>() + .children() + .flat_map(|node| { + if node.is::<HTMLOptionElement>() { + let node = Root::downcast::<HTMLOptionElement>(node).unwrap(); + Choice3::First(iter::once(node)) + } else if node.is::<HTMLOptGroupElement>() { + Choice3::Second(node.children().filter_map(Root::downcast)) + } else { + Choice3::Third(iter::empty()) + } + }) + } + // https://html.spec.whatwg.org/multipage/#the-select-element:concept-form-reset-control pub fn reset(&self) { - let node = self.upcast::<Node>(); - for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) { + for opt in self.list_of_options() { opt.set_selectedness(opt.DefaultSelected()); opt.set_dirtiness(false); } @@ -103,8 +119,7 @@ impl HTMLSelectElement { let mut first_enabled: Option<Root<HTMLOptionElement>> = None; let mut last_selected: Option<Root<HTMLOptionElement>> = None; - let node = self.upcast::<Node>(); - for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) { + for opt in self.list_of_options() { if opt.Selected() { opt.set_selectedness(false); last_selected = Some(Root::from_ref(&opt)); @@ -127,11 +142,10 @@ impl HTMLSelectElement { } pub fn push_form_data(&self, data_set: &mut Vec<FormDatum>) { - let node = self.upcast::<Node>(); if self.Name().is_empty() { return; } - for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) { + for opt in self.list_of_options() { let element = opt.upcast::<Element>(); if opt.Selected() && element.enabled_state() { data_set.push(FormDatum { @@ -146,9 +160,8 @@ impl HTMLSelectElement { // https://html.spec.whatwg.org/multipage/#concept-select-pick pub fn pick_option(&self, picked: &HTMLOptionElement) { if !self.Multiple() { - let node = self.upcast::<Node>(); let picked = picked.upcast(); - for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) { + for opt in self.list_of_options() { if opt.upcast::<HTMLElement>() != picked { opt.set_selectedness(false); } @@ -271,9 +284,7 @@ impl HTMLSelectElementMethods for HTMLSelectElement { // https://html.spec.whatwg.org/multipage/#dom-select-value fn Value(&self) -> DOMString { - self.upcast::<Node>() - .traverse_preorder() - .filter_map(Root::downcast::<HTMLOptionElement>) + self.list_of_options() .filter(|opt_elem| opt_elem.Selected()) .map(|opt_elem| opt_elem.Value()) .next() @@ -282,9 +293,7 @@ impl HTMLSelectElementMethods for HTMLSelectElement { // https://html.spec.whatwg.org/multipage/#dom-select-value fn SetValue(&self, value: DOMString) { - let mut opt_iter = self.upcast::<Node>() - .traverse_preorder() - .filter_map(Root::downcast::<HTMLOptionElement>); + let mut opt_iter = self.list_of_options(); // Reset until we find an <option> with a matching value for opt in opt_iter.by_ref() { if opt.Value() == value { @@ -302,9 +311,7 @@ impl HTMLSelectElementMethods for HTMLSelectElement { // https://html.spec.whatwg.org/multipage/#dom-select-selectedindex fn SelectedIndex(&self) -> i32 { - self.upcast::<Node>() - .traverse_preorder() - .filter_map(Root::downcast::<HTMLOptionElement>) + self.list_of_options() .enumerate() .filter(|&(_, ref opt_elem)| opt_elem.Selected()) .map(|(i, _)| i as i32) @@ -314,9 +321,7 @@ impl HTMLSelectElementMethods for HTMLSelectElement { // https://html.spec.whatwg.org/multipage/#dom-select-selectedindex fn SetSelectedIndex(&self, index: i32) { - let mut opt_iter = self.upcast::<Node>() - .traverse_preorder() - .filter_map(Root::downcast::<HTMLOptionElement>); + let mut opt_iter = self.list_of_options(); for opt in opt_iter.by_ref().take(index as usize) { opt.set_selectedness(false); } @@ -394,3 +399,23 @@ impl Validatable for HTMLSelectElement { true } } + +enum Choice3<I, J, K> { + First(I), + Second(J), + Third(K), +} + +impl<I, J, K, T> Iterator for Choice3<I, J, K> + where I: Iterator<Item=T>, J: Iterator<Item=T>, K: Iterator<Item=T> +{ + type Item = T; + + fn next(&mut self) -> Option<T> { + match *self { + Choice3::First(ref mut i) => i.next(), + Choice3::Second(ref mut j) => j.next(), + Choice3::Third(ref mut k) => k.next(), + } + } +} diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 3e6746c6922..79a1f5075eb 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -39725,6 +39725,12 @@ "timeout": "long", "url": "/html/semantics/forms/form-submission-0/submit-entity-body.html" } + ], + "html/semantics/forms/the-select-element/select-value.html": [ + { + "path": "html/semantics/forms/the-select-element/select-value.html", + "url": "/html/semantics/forms/the-select-element/select-value.html" + } ] } }, diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/select-value.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/select-value.html new file mode 100644 index 00000000000..d8d5263e3e7 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/select-value.html @@ -0,0 +1,56 @@ +<!doctype html> +<meta charset="utf-8"> +<title>HTMLSelectElement.value</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-select-value"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> + +<select id=sel1> + <option value=0></option> + <option selected value=1></option> +</select> + +<select id=sel2> + <optgroup> + <option value=0></option> + </optgroup> + <optgroup></optgroup> + <optgroup> + <option></option> + <option value=1></option> + <option selected value=2></option> + </optgroup> +</select> + +<select id=sel3> + <option selected value=1></option> +</select> + +<select id=sel4></select> + +<script> +test(function() { + var select = document.getElementById('sel1'); + assert_equals(select.value, '1'); +}, 'options'); + +test(function() { + var select = document.getElementById('sel2'); + assert_equals(select.value, '2'); +}, 'optgroups'); + +test(function() { + var select = document.getElementById('sel3'); + var option = select.options[0]; + var div = document.createElement('div'); + select.appendChild(div); + div.appendChild(option); + assert_equals(select.value, ''); +}, 'option is child of div'); + +test(function() { + var select = document.getElementById('sel4'); + assert_equals(select.value, ''); +}, 'no options'); +</script> |