diff --git a/src/components/script/dom/htmlcollection.rs b/src/components/script/dom/htmlcollection.rs index 77d36e07005..71f4f90a568 100644 --- a/src/components/script/dom/htmlcollection.rs +++ b/src/components/script/dom/htmlcollection.rs @@ -12,24 +12,40 @@ use dom::window::Window; use servo_util::namespace::Namespace; use servo_util::str::DOMString; +use serialize::{Encoder, Encodable}; + +pub trait CollectionFilter { + fn filter(&self, elem: &JS, root: &JS) -> bool; +} + +impl Encodable for ~CollectionFilter { + fn encode(&self, _s: &mut S) {} +} + +#[deriving(Encodable)] +pub enum CollectionTypeId { + Static(~[JS]), + Live(JS, ~CollectionFilter) +} + #[deriving(Encodable)] pub struct HTMLCollection { - elements: ~[JS], + collection: CollectionTypeId, reflector_: Reflector, window: JS, } impl HTMLCollection { - pub fn new_inherited(window: JS, elements: ~[JS]) -> HTMLCollection { + pub fn new_inherited(window: JS, collection: CollectionTypeId) -> HTMLCollection { HTMLCollection { - elements: elements, + collection: collection, reflector_: Reflector::new(), window: window, } } - pub fn new(window: &JS, elements: ~[JS]) -> JS { - reflect_dom_object(~HTMLCollection::new_inherited(window.clone(), elements), + pub fn new(window: &JS, collection: CollectionTypeId) -> JS { + reflect_dom_object(~HTMLCollection::new_inherited(window.clone(), collection), window, HTMLCollectionBinding::Wrap) } } @@ -45,7 +61,7 @@ impl HTMLCollection { } } } - HTMLCollection::new(window, elements) + HTMLCollection::new(window, Static(elements)) } pub fn by_tag_name(window: &JS, root: &JS, tag_name: DOMString) -> JS { @@ -66,15 +82,26 @@ impl HTMLCollection { impl HTMLCollection { // http://dom.spec.whatwg.org/#dom-htmlcollection-length pub fn Length(&self) -> u32 { - self.elements.len() as u32 + match self.collection { + Static(ref elems) => elems.len() as u32, + Live(ref root, ref filter) => root.traverse_preorder() + .count(|child| { + let elem: Option> = ElementCast::to(&child); + elem.map_or(false, |elem| filter.filter(&elem, root)) + }) as u32 + } } // http://dom.spec.whatwg.org/#dom-htmlcollection-item pub fn Item(&self, index: u32) -> Option> { - if index < self.Length() { - Some(self.elements[index].clone()) - } else { - None + match self.collection { + Static(ref elems) => elems + .get(index as uint) + .map(|elem| elem.clone()), + Live(ref root, ref filter) => root.traverse_preorder() + .filter_map(|node| ElementCast::to(&node)) + .filter(|elem| filter.filter(elem, root)) + .nth(index as uint).clone() } } @@ -86,9 +113,20 @@ impl HTMLCollection { } // Step 2. - self.elements.iter().find(|elem| { - elem.get_string_attribute("name") == key || elem.get_string_attribute("id") == key - }).map(|maybe_elem| maybe_elem.clone()) + match self.collection { + Static(ref elems) => elems.iter() + .find(|elem| { + elem.get_string_attribute("name") == key || + elem.get_string_attribute("id") == key }) + .map(|maybe_elem| maybe_elem.clone()), + Live(ref root, ref filter) => root.traverse_preorder() + .filter_map(|node| ElementCast::to(&node)) + .filter(|elem| filter.filter(elem, root)) + .find(|elem| { + elem.get_string_attribute("name") == key || + elem.get_string_attribute("id") == key }) + .map(|maybe_elem| maybe_elem.clone()) + } } } diff --git a/src/components/script/dom/htmlformelement.rs b/src/components/script/dom/htmlformelement.rs index a1ca7d5dc2f..cabb71cc1ea 100644 --- a/src/components/script/dom/htmlformelement.rs +++ b/src/components/script/dom/htmlformelement.rs @@ -9,7 +9,7 @@ use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::{Element, HTMLFormElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; -use dom::htmlcollection::HTMLCollection; +use dom::htmlcollection::{HTMLCollection, Static}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId}; use servo_util::str::DOMString; @@ -118,7 +118,7 @@ impl HTMLFormElement { // FIXME: https://github.com/mozilla/servo/issues/1844 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); - HTMLCollection::new(&doc.window, ~[]) + HTMLCollection::new(&doc.window, Static(~[])) } pub fn Length(&self) -> i32 { diff --git a/src/components/script/dom/htmlmapelement.rs b/src/components/script/dom/htmlmapelement.rs index d343073a278..c439225362c 100644 --- a/src/components/script/dom/htmlmapelement.rs +++ b/src/components/script/dom/htmlmapelement.rs @@ -9,7 +9,7 @@ use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::HTMLMapElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; -use dom::htmlcollection::HTMLCollection; +use dom::htmlcollection::{HTMLCollection, Static}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId}; use servo_util::str::DOMString; @@ -54,6 +54,6 @@ impl HTMLMapElement { // FIXME: https://github.com/mozilla/servo/issues/1845 let doc = self.htmlelement.element.node.owner_doc(); let doc = doc.get(); - HTMLCollection::new(&doc.window, ~[]) + HTMLCollection::new(&doc.window, Static(~[])) } }