diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 9854bb7e386..b699f63f50f 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -478,20 +478,31 @@ impl Document { self.window.get().wait_until_safe_to_modify_dom(); } - pub fn register_nodes_with_id(&mut self, root: &JS) { - foreach_ided_elements(root, |id: &DOMString, abstract_node: &JS| { - // TODO: "in tree order, within the context object's tree" - // http://dom.spec.whatwg.org/#dom-document-getelementbyid. - self.idmap.find_or_insert(id.clone(), abstract_node.clone()); - }); + + /// Remove any existing association between the provided id and any elements in this document. + pub fn unregister_named_element(&mut self, + id: DOMString) { + self.idmap.remove(&id); } - pub fn unregister_nodes_with_id(&mut self, root: &JS) { - foreach_ided_elements(root, |id: &DOMString, _| { - // TODO: "in tree order, within the context object's tree" - // http://dom.spec.whatwg.org/#dom-document-getelementbyid. - self.idmap.pop(id); + /// Associate an element present in this document with the provided id. + pub fn register_named_element(&mut self, + element: &JS, + id: DOMString) { + assert!({ + let node: JS = NodeCast::from(element); + node.is_in_doc() }); + + // TODO: support the case if multiple elements + // which haves same id are in the same document. + self.idmap.mangle(id, element, + |_, new_element: &JS| -> JS { + new_element.clone() + }, + |_, old_element: &mut JS, new_element: &JS| { + *old_element = new_element.clone(); + }); } pub fn update_idmap(&mut self, @@ -525,21 +536,3 @@ impl Document { } } } - -#[inline(always)] -fn foreach_ided_elements(root: &JS, callback: |&DOMString, &JS|) { - let root: JS = NodeCast::from(root); - for node in root.traverse_preorder() { - if !node.is_element() { - continue; - } - - let element: JS = ElementCast::to(&node); - match element.get().get_attribute(Null, "id") { - Some(id) => { - callback(&id.get().Value(), &element); - } - None => () - } - } -} diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index d7bbaa065a6..eed0bc9b237 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -646,6 +646,33 @@ impl Element { } } +pub trait IElement { + fn bind_to_tree_impl(&self); + fn unbind_from_tree_impl(&self); +} + +impl IElement for JS { + fn bind_to_tree_impl(&self) { + match self.get().get_attribute(Null, "id") { + Some(attr) => { + let mut doc = self.get().node.owner_doc(); + doc.get_mut().register_named_element(self, attr.get().Value()); + } + _ => () + } + } + + fn unbind_from_tree_impl(&self) { + match self.get().get_attribute(Null, "id") { + Some(attr) => { + let mut doc = self.get().node.owner_doc(); + doc.get_mut().unregister_named_element(attr.get().Value()); + } + _ => () + } + } +} + fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) { //FIXME: Throw for XML-invalid names //FIXME: Throw for XMLNS-invalid names diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index a0357c92ab4..419b02c844a 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -14,7 +14,7 @@ use dom::bindings::utils; use dom::characterdata::CharacterData; use dom::document::Document; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId}; +use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId, IElement}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::nodelist::{NodeList}; use dom::text::Text; @@ -396,11 +396,13 @@ impl NodeHelpers for JS { // http://dom.spec.whatwg.org/#node-is-inserted fn node_inserted(&self) { assert!(self.parent_node().is_some()); - let mut document = self.get().owner_doc(); + let document = self.get().owner_doc(); - // Register elements having "id" attribute to the owner doc. - if self.is_element() { - document.get_mut().register_nodes_with_id(&ElementCast::to(self)); + for node in self.traverse_preorder() { + if node.is_element() { + let element: JS = ElementCast::to(&node); + element.bind_to_tree_impl(); + } } document.get().content_changed(); @@ -409,11 +411,13 @@ impl NodeHelpers for JS { // http://dom.spec.whatwg.org/#node-is-removed fn node_removed(&self) { assert!(self.parent_node().is_none()); - let mut document = self.get().owner_doc(); + let document = self.get().owner_doc(); - // Unregister elements having "id". - if self.is_element() { - document.get_mut().unregister_nodes_with_id(&ElementCast::to(self)); + for node in self.traverse_preorder() { + if node.is_element() { + let element: JS = ElementCast::to(&node); + element.unbind_from_tree_impl(); + } } document.get().content_changed();