mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Implement NamedItem and NamedGetter on HTMLFormControlsCollection
This commit is contained in:
parent
9e3af70941
commit
4229b68062
10 changed files with 94 additions and 140 deletions
|
@ -5,13 +5,17 @@
|
||||||
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
|
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
|
||||||
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
|
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
|
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
|
||||||
|
use dom::bindings::codegen::UnionTypes::RadioNodeListOrElement::{self, eElement, eRadioNodeList};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
|
use dom::bindings::inheritance::Castable;
|
||||||
use dom::bindings::js::Root;
|
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::element::Element;
|
||||||
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
||||||
use dom::node::Node;
|
use dom::node::Node;
|
||||||
|
use dom::radionodelist::RadioNodeList;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
|
use std::iter;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -43,8 +47,41 @@ impl HTMLFormControlsCollection {
|
||||||
|
|
||||||
impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
|
impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
|
// https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
|
||||||
fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<Root<Element>> {
|
fn NamedItem(&self, name: DOMString) -> Option<RadioNodeListOrElement> {
|
||||||
self.collection.NamedGetter(name, found)
|
// 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::<Node>(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<RadioNodeListOrElement> {
|
||||||
|
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
|
// https://html.spec.whatwg.org/multipage/#the-htmlformcontrolscollection-interface:supported-property-names
|
||||||
|
|
|
@ -41,8 +41,7 @@ impl NodeList {
|
||||||
GlobalRef::Window(window), NodeListBinding::Wrap)
|
GlobalRef::Window(window), NodeListBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_simple_list<T>(window: &Window, iter: T)
|
pub fn new_simple_list<T>(window: &Window, iter: T) -> Root<NodeList>
|
||||||
-> Root<NodeList>
|
|
||||||
where T: Iterator<Item=Root<Node>> {
|
where T: Iterator<Item=Root<Node>> {
|
||||||
NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
|
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 {
|
pub fn as_simple_list(&self) -> &Vec<JS<Node>> {
|
||||||
&self.list_type
|
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 {
|
impl ChildrenList {
|
||||||
fn new(node: &Node) -> ChildrenList {
|
pub fn new(node: &Node) -> ChildrenList {
|
||||||
let last_visited = node.GetFirstChild();
|
let last_visited = node.GetFirstChild();
|
||||||
ChildrenList {
|
ChildrenList {
|
||||||
node: JS::from_ref(node),
|
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 {
|
pub fn len(&self) -> u32 {
|
||||||
self.node.children_count()
|
self.node.children_count()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::RadioNodeListBinding;
|
||||||
use dom::bindings::codegen::Bindings::RadioNodeListBinding::RadioNodeListMethods;
|
use dom::bindings::codegen::Bindings::RadioNodeListBinding::RadioNodeListMethods;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::inheritance::Castable;
|
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::bindings::reflector::reflect_dom_object;
|
||||||
use dom::htmlinputelement::HTMLInputElement;
|
use dom::htmlinputelement::HTMLInputElement;
|
||||||
use dom::node::Node;
|
use dom::node::Node;
|
||||||
|
@ -36,6 +36,15 @@ impl RadioNodeList {
|
||||||
RadioNodeListBinding::Wrap)
|
RadioNodeListBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_simple_list<T>(window: &Window, iter: T) -> Root<RadioNodeList>
|
||||||
|
where T: Iterator<Item=Root<Node>> {
|
||||||
|
RadioNodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty(window: &Window) -> Root<RadioNodeList> {
|
||||||
|
RadioNodeList::new(window, NodeListType::Simple(vec![]))
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
|
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
|
||||||
// RadioNodeList) implements Length
|
// RadioNodeList) implements Length
|
||||||
// https://github.com/servo/servo/issues/5875
|
// https://github.com/servo/servo/issues/5875
|
||||||
|
@ -47,98 +56,48 @@ impl RadioNodeList {
|
||||||
impl RadioNodeListMethods for RadioNodeList {
|
impl RadioNodeListMethods for RadioNodeList {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-radionodelist-value
|
// https://html.spec.whatwg.org/multipage/#dom-radionodelist-value
|
||||||
fn Value(&self) -> DOMString {
|
fn Value(&self) -> DOMString {
|
||||||
match *self.upcast::<NodeList>().get_list_type() {
|
self.upcast::<NodeList>().as_simple_list().iter().filter_map(|node| {
|
||||||
NodeListType::Simple(ref v) => {
|
// Step 1
|
||||||
v.iter().filter_map(|node| {
|
node.downcast::<HTMLInputElement>().and_then(|input| {
|
||||||
// Step 1
|
match input.type_() {
|
||||||
node.downcast::<HTMLInputElement>().and_then(|input| {
|
atom!("radio") if input.Checked() => {
|
||||||
match input.type_() {
|
// Step 3-4
|
||||||
atom!("radio") if input.Checked() => {
|
let value = input.Value();
|
||||||
// Step 3-4
|
Some(if value.is_empty() { DOMString::from("on") } else { value })
|
||||||
let value = input.Value();
|
}
|
||||||
Some(if value.is_empty() { DOMString::from("on") } else { value })
|
_ => None
|
||||||
}
|
}
|
||||||
_ => None
|
})
|
||||||
}
|
}).next()
|
||||||
})
|
// Step 2
|
||||||
}).next()
|
.unwrap_or(DOMString::from(""))
|
||||||
// Step 2
|
|
||||||
.unwrap_or(DOMString::from(""))
|
|
||||||
}
|
|
||||||
NodeListType::Children(ref cl) => {
|
|
||||||
cl.get_parent_node().traverse_preorder().filter_map(|node| {
|
|
||||||
// Step 1
|
|
||||||
node.downcast::<HTMLInputElement>().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) {
|
fn SetValue(&self, value: DOMString) {
|
||||||
match *self.upcast::<NodeList>().get_list_type() {
|
for node in self.upcast::<NodeList>().as_simple_list().iter() {
|
||||||
NodeListType::Simple(ref v) => {
|
// Step 1
|
||||||
for node in v.iter() {
|
if let Some(input) = node.downcast::<HTMLInputElement>() {
|
||||||
// Step 1
|
match input.type_() {
|
||||||
if let Some(input) = node.downcast::<HTMLInputElement>() {
|
atom!("radio") if value == DOMString::from("on") => {
|
||||||
match input.type_() {
|
// Step 2
|
||||||
atom!("radio") if value == DOMString::from("on") => {
|
let val = input.Value();
|
||||||
// Step 2
|
if val.is_empty() || val == value {
|
||||||
let val = input.Value();
|
input.SetChecked(true);
|
||||||
if val.is_empty() || val == DOMString::from("on") {
|
return;
|
||||||
input.SetChecked(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
atom!("radio") => {
|
|
||||||
// Step 2
|
|
||||||
if input.Value() == value {
|
|
||||||
input.SetChecked(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
atom!("radio") => {
|
||||||
}
|
// Step 2
|
||||||
NodeListType::Children(ref cl) => {
|
if input.Value() == value {
|
||||||
for node in cl.get_parent_node().traverse_preorder() {
|
input.SetChecked(true);
|
||||||
// Step 1
|
return;
|
||||||
if let Some(input) = node.downcast::<HTMLInputElement>() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
|
// FIXME: This shouldn't need to be implemented here since NodeList (the parent of
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
// https://html.spec.whatwg.org/multipage/#htmlformcontrolscollection
|
// https://html.spec.whatwg.org/multipage/#htmlformcontrolscollection
|
||||||
interface HTMLFormControlsCollection : HTMLCollection {
|
interface HTMLFormControlsCollection : HTMLCollection {
|
||||||
// inherits length and item()
|
// inherits length and item()
|
||||||
// getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem()
|
getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem()
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#radionodelist
|
// https://html.spec.whatwg.org/multipage/#radionodelist
|
||||||
interface RadioNodeList : NodeList {
|
interface RadioNodeList : NodeList {
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1359,9 +1359,6 @@
|
||||||
[HTMLCollection interface: calling namedItem(DOMString) on document.all with too few arguments must throw TypeError]
|
[HTMLCollection interface: calling namedItem(DOMString) on document.all with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLFormControlsCollection interface: operation namedItem(DOMString)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLFormControlsCollection must be primary interface of document.createElement("form").elements]
|
[HTMLFormControlsCollection must be primary interface of document.createElement("form").elements]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -1389,21 +1386,6 @@
|
||||||
[HTMLCollection interface: calling namedItem(DOMString) on document.createElement("form").elements with too few arguments must throw TypeError]
|
[HTMLCollection interface: calling namedItem(DOMString) on document.createElement("form").elements with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
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]
|
[HTMLOptionsCollection interface: existence and properties of interface object]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -8946,9 +8928,6 @@
|
||||||
[HTMLAllCollection interface object name]
|
[HTMLAllCollection interface object name]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[RadioNodeList interface object name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLOptionsCollection interface object name]
|
[HTMLOptionsCollection interface object name]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,9 @@
|
||||||
[HTMLFormControlsCollection(name) must return the named item]
|
[HTMLFormControlsCollection(name) must return the named item]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[The namedItem(name) must return RadioNodeList]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Controls can be indexed by id or name attribute]
|
[Controls can be indexed by id or name attribute]
|
||||||
expected: FAIL
|
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]
|
[The HTMLFormControlsCollection interface is used for collections of listed elements in form element]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
[radionodelist.html]
|
[radionodelist.html]
|
||||||
type: testharness
|
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']
|
[Check the RadioNodeList.value on setting to 'on']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
[form-elements-nameditem-01.html]
|
[form-elements-nameditem-01.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[RadioNodeList should exist]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[elements collection should return elements or RadioNodeLists]
|
[elements collection should return elements or RadioNodeLists]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@ var interfaceNamesInGlobalScope = [
|
||||||
"PerformanceTiming",
|
"PerformanceTiming",
|
||||||
"ProcessingInstruction",
|
"ProcessingInstruction",
|
||||||
"ProgressEvent",
|
"ProgressEvent",
|
||||||
|
"RadioNodeList",
|
||||||
"Range",
|
"Range",
|
||||||
"Screen",
|
"Screen",
|
||||||
"Storage",
|
"Storage",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue