diff --git a/components/script/dom/htmlformcontrolscollection.rs b/components/script/dom/htmlformcontrolscollection.rs
index be6c72b2d2e..734878d75c4 100644
--- a/components/script/dom/htmlformcontrolscollection.rs
+++ b/components/script/dom/htmlformcontrolscollection.rs
@@ -5,13 +5,17 @@
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
+use dom::bindings::codegen::UnionTypes::RadioNodeListOrElement::{self, eElement, eRadioNodeList};
use dom::bindings::global::GlobalRef;
+use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
-use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::element::Element;
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
use dom::node::Node;
+use dom::radionodelist::RadioNodeList;
use dom::window::Window;
+use std::iter;
use util::str::DOMString;
#[dom_struct]
@@ -43,8 +47,41 @@ impl HTMLFormControlsCollection {
impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
// https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
- fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option> {
- self.collection.NamedGetter(name, found)
+ fn NamedItem(&self, name: DOMString) -> Option {
+ // Step 1
+ if name.is_empty() { return None; }
+
+ let mut filter_map = self.collection.elements_iter().filter_map(|elem| {
+ if elem.get_string_attribute(&atom!("name")) == name
+ || elem.get_string_attribute(&atom!("id")) == name {
+ Some(elem)
+ } else { None }
+ });
+
+ if let Some(elem) = filter_map.next() {
+ let mut peekable = filter_map.peekable();
+ // Step 2
+ if peekable.peek().is_none() {
+ Some(eElement(elem))
+ } else {
+ // Step 4-5
+ let once = iter::once(Root::upcast::(elem));
+ let list = once.chain(peekable.map(Root::upcast));
+ let global = self.global();
+ let global = global.r();
+ let window = global.as_window();
+ Some(eRadioNodeList(RadioNodeList::new_simple_list(window, list)))
+ }
+ // Step 3
+ } else { None }
+
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
+ fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option {
+ let maybe_elem = self.NamedItem(name);
+ *found = maybe_elem.is_some();
+ maybe_elem
}
// https://html.spec.whatwg.org/multipage/#the-htmlformcontrolscollection-interface:supported-property-names
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index 5987b1b26f0..2d1bbe363a7 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -41,8 +41,7 @@ impl NodeList {
GlobalRef::Window(window), NodeListBinding::Wrap)
}
- pub fn new_simple_list(window: &Window, iter: T)
- -> Root
+ pub fn new_simple_list(window: &Window, iter: T) -> Root
where T: Iterator- > {
NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
}
@@ -93,8 +92,12 @@ impl NodeList {
}
}
- pub fn get_list_type(&self) -> &NodeListType {
- &self.list_type
+ pub fn as_simple_list(&self) -> &Vec> {
+ if let NodeListType::Simple(ref list) = self.list_type {
+ list
+ } else {
+ panic!("called as_simple_list() on a children node list")
+ }
}
}
@@ -108,7 +111,7 @@ pub struct ChildrenList {
}
impl ChildrenList {
- fn new(node: &Node) -> ChildrenList {
+ pub fn new(node: &Node) -> ChildrenList {
let last_visited = node.GetFirstChild();
ChildrenList {
node: JS::from_ref(node),
@@ -117,10 +120,6 @@ impl ChildrenList {
}
}
- pub fn get_parent_node(&self) -> &Node {
- &*self.node
- }
-
pub fn len(&self) -> u32 {
self.node.children_count()
}
diff --git a/components/script/dom/radionodelist.rs b/components/script/dom/radionodelist.rs
index ebb9909f1d6..ae6ac13919d 100644
--- a/components/script/dom/radionodelist.rs
+++ b/components/script/dom/radionodelist.rs
@@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::RadioNodeListBinding;
use dom::bindings::codegen::Bindings::RadioNodeListBinding::RadioNodeListMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
-use dom::bindings::js::Root;
+use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::reflect_dom_object;
use dom::htmlinputelement::HTMLInputElement;
use dom::node::Node;
@@ -36,6 +36,15 @@ impl RadioNodeList {
RadioNodeListBinding::Wrap)
}
+ pub fn new_simple_list(window: &Window, iter: T) -> Root
+ where T: Iterator
- > {
+ RadioNodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
+ }
+
+ pub fn empty(window: &Window) -> Root {
+ RadioNodeList::new(window, NodeListType::Simple(vec![]))
+ }
+
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
// RadioNodeList) implements Length
// https://github.com/servo/servo/issues/5875
@@ -47,98 +56,48 @@ impl RadioNodeList {
impl RadioNodeListMethods for RadioNodeList {
// https://html.spec.whatwg.org/multipage/#dom-radionodelist-value
fn Value(&self) -> DOMString {
- match *self.upcast::().get_list_type() {
- NodeListType::Simple(ref v) => {
- v.iter().filter_map(|node| {
- // Step 1
- node.downcast::().and_then(|input| {
- match input.type_() {
- atom!("radio") if input.Checked() => {
- // Step 3-4
- let value = input.Value();
- Some(if value.is_empty() { DOMString::from("on") } else { value })
- }
- _ => None
- }
- })
- }).next()
- // Step 2
- .unwrap_or(DOMString::from(""))
- }
- NodeListType::Children(ref cl) => {
- cl.get_parent_node().traverse_preorder().filter_map(|node| {
- // Step 1
- node.downcast::().and_then(|input| {
- match input.type_() {
- atom!("radio") if input.Checked() => {
- // Step 3-4
- let value = input.Value();
- Some(if value.is_empty() { DOMString::from("on") } else { value })
- }
- _ => None
- }
- })
- }).next()
- // Step 2
- .unwrap_or(DOMString::from(""))
- }
- }
+ self.upcast::().as_simple_list().iter().filter_map(|node| {
+ // Step 1
+ node.downcast::().and_then(|input| {
+ match input.type_() {
+ atom!("radio") if input.Checked() => {
+ // Step 3-4
+ let value = input.Value();
+ Some(if value.is_empty() { DOMString::from("on") } else { value })
+ }
+ _ => None
+ }
+ })
+ }).next()
+ // Step 2
+ .unwrap_or(DOMString::from(""))
}
- // https://html.spec.whatwg.org/multipage/infrastructure.html#dom-radionodelist-value
+ // https://html.spec.whatwg.org/multipage/#dom-radionodelist-value
fn SetValue(&self, value: DOMString) {
- match *self.upcast::().get_list_type() {
- NodeListType::Simple(ref v) => {
- for node in v.iter() {
- // Step 1
- if let Some(input) = node.downcast::() {
- match input.type_() {
- atom!("radio") if value == DOMString::from("on") => {
- // Step 2
- let val = input.Value();
- if val.is_empty() || val == DOMString::from("on") {
- input.SetChecked(true);
- return;
- }
- }
- atom!("radio") => {
- // Step 2
- if input.Value() == value {
- input.SetChecked(true);
- return;
- }
- }
- _ => {}
+ for node in self.upcast::().as_simple_list().iter() {
+ // Step 1
+ if let Some(input) = node.downcast::() {
+ match input.type_() {
+ atom!("radio") if value == DOMString::from("on") => {
+ // Step 2
+ let val = input.Value();
+ if val.is_empty() || val == value {
+ input.SetChecked(true);
+ return;
}
}
- }
- }
- NodeListType::Children(ref cl) => {
- for node in cl.get_parent_node().traverse_preorder() {
- // Step 1
- if let Some(input) = node.downcast::() {
- match input.type_() {
- atom!("radio") if value == DOMString::from("on") => {
- // Step 2
- let val = input.Value();
- if val.is_empty() || val == DOMString::from("on") {
- input.SetChecked(true);
- return;
- }
- }
- atom!("radio") => {
- // Step 2
- if input.Value() == value {
- input.SetChecked(true);
- return;
- }
- }
- _ => {}
+ atom!("radio") => {
+ // Step 2
+ if input.Value() == value {
+ input.SetChecked(true);
+ return;
}
}
+ _ => {}
}
}
- };
+ }
}
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
diff --git a/components/script/dom/webidls/HTMLFormControlsCollection.webidl b/components/script/dom/webidls/HTMLFormControlsCollection.webidl
index c4a26c7b20c..0e81285575b 100644
--- a/components/script/dom/webidls/HTMLFormControlsCollection.webidl
+++ b/components/script/dom/webidls/HTMLFormControlsCollection.webidl
@@ -6,5 +6,5 @@
// https://html.spec.whatwg.org/multipage/#htmlformcontrolscollection
interface HTMLFormControlsCollection : HTMLCollection {
// inherits length and item()
- // getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem()
+ getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem()
};
diff --git a/components/script/dom/webidls/RadioNodeList.webidl b/components/script/dom/webidls/RadioNodeList.webidl
index d3c1ed892dc..9ab1d7ea5f0 100644
--- a/components/script/dom/webidls/RadioNodeList.webidl
+++ b/components/script/dom/webidls/RadioNodeList.webidl
@@ -5,5 +5,5 @@
// https://html.spec.whatwg.org/multipage/#radionodelist
interface RadioNodeList : NodeList {
- attribute DOMString value;
+ attribute DOMString value;
};
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index 02806e334df..d4e5846bc89 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -1359,9 +1359,6 @@
[HTMLCollection interface: calling namedItem(DOMString) on document.all with too few arguments must throw TypeError]
expected: FAIL
- [HTMLFormControlsCollection interface: operation namedItem(DOMString)]
- expected: FAIL
-
[HTMLFormControlsCollection must be primary interface of document.createElement("form").elements]
expected: FAIL
@@ -1389,21 +1386,6 @@
[HTMLCollection interface: calling namedItem(DOMString) on document.createElement("form").elements with too few arguments must throw TypeError]
expected: FAIL
- [RadioNodeList interface: existence and properties of interface object]
- expected: FAIL
-
- [RadioNodeList interface object length]
- expected: FAIL
-
- [RadioNodeList interface: existence and properties of interface prototype object]
- expected: FAIL
-
- [RadioNodeList interface: existence and properties of interface prototype object's "constructor" property]
- expected: FAIL
-
- [RadioNodeList interface: attribute value]
- expected: FAIL
-
[HTMLOptionsCollection interface: existence and properties of interface object]
expected: FAIL
@@ -8946,9 +8928,6 @@
[HTMLAllCollection interface object name]
expected: FAIL
- [RadioNodeList interface object name]
- expected: FAIL
-
[HTMLOptionsCollection interface object name]
expected: FAIL
diff --git a/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/htmlformcontrolscollection.html.ini b/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/htmlformcontrolscollection.html.ini
index 5fb543d2eed..2daa58b237e 100644
--- a/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/htmlformcontrolscollection.html.ini
+++ b/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/htmlformcontrolscollection.html.ini
@@ -6,15 +6,9 @@
[HTMLFormControlsCollection(name) must return the named item]
expected: FAIL
- [The namedItem(name) must return RadioNodeList]
- expected: FAIL
-
[Controls can be indexed by id or name attribute]
expected: FAIL
- [The namedItem(name) must return the items with id or name attribute]
- expected: FAIL
-
[The HTMLFormControlsCollection interface is used for collections of listed elements in form element]
expected: FAIL
diff --git a/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/radionodelist.html.ini b/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/radionodelist.html.ini
index a4c1cf16d69..d1621994aa7 100644
--- a/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/radionodelist.html.ini
+++ b/tests/wpt/metadata/html/infrastructure/common-dom-interfaces/collections/radionodelist.html.ini
@@ -1,17 +1,5 @@
[radionodelist.html]
type: testharness
- [The value attribute should be empty if no element is checked]
- expected: FAIL
-
- [The RadioNodeList.value must be the first checked radio button's value]
- expected: FAIL
-
- [Check the RadioNodeList.value on getting]
- expected: FAIL
-
- [Check the RadioNodeList.value on setting]
- expected: FAIL
-
[Check the RadioNodeList.value on setting to 'on']
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/forms/the-form-element/form-elements-nameditem-01.html.ini b/tests/wpt/metadata/html/semantics/forms/the-form-element/form-elements-nameditem-01.html.ini
index b9425920944..84bdf90a6cb 100644
--- a/tests/wpt/metadata/html/semantics/forms/the-form-element/form-elements-nameditem-01.html.ini
+++ b/tests/wpt/metadata/html/semantics/forms/the-form-element/form-elements-nameditem-01.html.ini
@@ -1,8 +1,5 @@
[form-elements-nameditem-01.html]
type: testharness
- [RadioNodeList should exist]
- expected: FAIL
-
[elements collection should return elements or RadioNodeLists]
expected: FAIL
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index 2d63e0a60b2..b8a664c166f 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -193,6 +193,7 @@ var interfaceNamesInGlobalScope = [
"PerformanceTiming",
"ProcessingInstruction",
"ProgressEvent",
+ "RadioNodeList",
"Range",
"Screen",
"Storage",