From 4229b68062a603a14a63952c0e010de3b0145c15 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 22 Jan 2016 22:44:48 -0500 Subject: [PATCH] Implement NamedItem and NamedGetter on HTMLFormControlsCollection --- .../script/dom/htmlformcontrolscollection.rs | 43 +++++- components/script/dom/nodelist.rs | 17 ++- components/script/dom/radionodelist.rs | 127 ++++++------------ .../webidls/HTMLFormControlsCollection.webidl | 2 +- .../script/dom/webidls/RadioNodeList.webidl | 2 +- .../wpt/metadata/html/dom/interfaces.html.ini | 21 --- .../htmlformcontrolscollection.html.ini | 6 - .../collections/radionodelist.html.ini | 12 -- .../form-elements-nameditem-01.html.ini | 3 - .../wpt/mozilla/tests/mozilla/interfaces.html | 1 + 10 files changed, 94 insertions(+), 140 deletions(-) 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",