mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #9407 - KiChjang:radio-node-list, r=nox
Implement RadioNodeList I also had to implement the NamedGetter for HTMLFormControlsCollection as well, since that's the only consumer of RadioNodeList and I wanted to see which wpt test passes. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9407) <!-- Reviewable:end -->
This commit is contained in:
commit
0c5591a8ec
12 changed files with 178 additions and 60 deletions
|
@ -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<Root<Element>> {
|
||||
self.collection.NamedGetter(name, found)
|
||||
fn NamedItem(&self, name: DOMString) -> Option<RadioNodeListOrElement> {
|
||||
// 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
|
||||
|
|
|
@ -341,6 +341,7 @@ pub mod performance;
|
|||
pub mod performancetiming;
|
||||
pub mod processinginstruction;
|
||||
pub mod progressevent;
|
||||
pub mod radionodelist;
|
||||
pub mod range;
|
||||
pub mod screen;
|
||||
pub mod servohtmlparser;
|
||||
|
|
|
@ -28,7 +28,7 @@ pub struct NodeList {
|
|||
|
||||
impl NodeList {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(list_type: NodeListType) -> NodeList {
|
||||
pub fn new_inherited(list_type: NodeListType) -> NodeList {
|
||||
NodeList {
|
||||
reflector_: Reflector::new(),
|
||||
list_type: list_type,
|
||||
|
@ -36,14 +36,12 @@ impl NodeList {
|
|||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window,
|
||||
list_type: NodeListType) -> Root<NodeList> {
|
||||
pub fn new(window: &Window, list_type: NodeListType) -> Root<NodeList> {
|
||||
reflect_dom_object(box NodeList::new_inherited(list_type),
|
||||
GlobalRef::Window(window), NodeListBinding::Wrap)
|
||||
}
|
||||
|
||||
pub fn new_simple_list<T>(window: &Window, iter: T)
|
||||
-> Root<NodeList>
|
||||
pub fn new_simple_list<T>(window: &Window, iter: T) -> Root<NodeList>
|
||||
where T: Iterator<Item=Root<Node>> {
|
||||
NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
|
||||
}
|
||||
|
@ -93,6 +91,14 @@ impl NodeList {
|
|||
panic!("called as_children_list() on a simple node list")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_simple_list(&self) -> &Vec<JS<Node>> {
|
||||
if let NodeListType::Simple(ref list) = self.list_type {
|
||||
list
|
||||
} else {
|
||||
panic!("called as_simple_list() on a children node list")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, HeapSizeOf)]
|
||||
|
@ -105,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),
|
||||
|
|
111
components/script/dom/radionodelist.rs
Normal file
111
components/script/dom/radionodelist.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
|
||||
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::{JS, Root};
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::htmlinputelement::HTMLInputElement;
|
||||
use dom::node::Node;
|
||||
use dom::nodelist::{NodeList, NodeListType};
|
||||
use dom::window::Window;
|
||||
use util::str::DOMString;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct RadioNodeList {
|
||||
node_list: NodeList,
|
||||
}
|
||||
|
||||
impl RadioNodeList {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(list_type: NodeListType) -> RadioNodeList {
|
||||
RadioNodeList {
|
||||
node_list: NodeList::new_inherited(list_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, list_type: NodeListType) -> Root<RadioNodeList> {
|
||||
reflect_dom_object(box RadioNodeList::new_inherited(list_type),
|
||||
GlobalRef::Window(window),
|
||||
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
|
||||
// RadioNodeList) implements Length
|
||||
// https://github.com/servo/servo/issues/5875
|
||||
pub fn Length(&self) -> u32 {
|
||||
self.node_list.Length()
|
||||
}
|
||||
}
|
||||
|
||||
impl RadioNodeListMethods for RadioNodeList {
|
||||
// https://html.spec.whatwg.org/multipage/#dom-radionodelist-value
|
||||
fn Value(&self) -> DOMString {
|
||||
self.upcast::<NodeList>().as_simple_list().iter().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/#dom-radionodelist-value
|
||||
fn SetValue(&self, value: DOMString) {
|
||||
for node in self.upcast::<NodeList>().as_simple_list().iter() {
|
||||
// Step 1
|
||||
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 == 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
|
||||
// RadioNodeList) implements IndexedGetter.
|
||||
// https://github.com/servo/servo/issues/5875
|
||||
//
|
||||
// https://dom.spec.whatwg.org/#dom-nodelist-item
|
||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Root<Node>> {
|
||||
self.node_list.IndexedGetter(index, found)
|
||||
}
|
||||
}
|
|
@ -6,11 +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()
|
||||
};
|
||||
|
||||
/*
|
||||
interface RadioNodeList : NodeList {
|
||||
attribute DOMString value;
|
||||
};
|
||||
*/
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
*/
|
||||
|
||||
interface NodeList {
|
||||
[Pure]
|
||||
readonly attribute unsigned long length;
|
||||
[Pure]
|
||||
getter Node? item(unsigned long index);
|
||||
[Pure]
|
||||
readonly attribute unsigned long length;
|
||||
// iterable<Node>;
|
||||
};
|
||||
|
|
9
components/script/dom/webidls/RadioNodeList.webidl
Normal file
9
components/script/dom/webidls/RadioNodeList.webidl
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#radionodelist
|
||||
interface RadioNodeList : NodeList {
|
||||
attribute DOMString value;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue