aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/script/dom/attr.rs95
-rw-r--r--src/components/script/dom/bindings/codegen/Attr.webidl18
-rw-r--r--src/components/script/dom/bindings/codegen/Bindings.conf5
-rw-r--r--src/components/script/dom/bindings/utils.rs34
-rw-r--r--src/components/script/dom/document.rs5
-rw-r--r--src/components/script/dom/element.rs175
-rw-r--r--src/components/script/dom/namespace.rs44
-rw-r--r--src/components/script/html/hubbub_html_parser.rs8
-rw-r--r--src/components/script/script.rc2
-rw-r--r--src/components/style/selector_matching.rs6
-rw-r--r--src/components/util/tree.rs4
11 files changed, 333 insertions, 63 deletions
diff --git a/src/components/script/dom/attr.rs b/src/components/script/dom/attr.rs
new file mode 100644
index 00000000000..310dc2f3de6
--- /dev/null
+++ b/src/components/script/dom/attr.rs
@@ -0,0 +1,95 @@
+/* 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::AttrBinding;
+use dom::bindings::utils::{Reflectable, Reflector, DOMString};
+use dom::bindings::utils::{reflect_dom_object, null_str_as_empty};
+use dom::namespace::{Namespace, Null};
+use dom::window::Window;
+
+use std::str::eq_slice;
+
+pub struct Attr {
+ reflector_: Reflector,
+ priv local_name: Option<~str>,
+ value: ~str,
+ name: ~str,
+ namespace: Namespace,
+ prefix: DOMString
+}
+
+impl Reflectable for Attr {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ &self.reflector_
+ }
+
+ fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
+ &mut self.reflector_
+ }
+}
+
+impl Attr {
+ fn new_inherited(name: ~str, value: ~str, local_name: Option<~str>,
+ namespace: Namespace, prefix: Option<~str>) -> Attr {
+ Attr {
+ reflector_: Reflector::new(),
+ local_name: local_name,
+ value: value,
+ name: name, //TODO: Intern attribute names
+ namespace: namespace,
+ prefix: prefix
+ }
+ }
+
+ pub fn new(window: &Window, name: ~str, value: ~str) -> @mut Attr {
+ Attr::new_helper(window, name, value, None, Null, None)
+ }
+
+ pub fn new_ns(window: &Window, name: ~str, value: ~str, local_name: ~str, namespace: Namespace,
+ prefix: Option<~str>) -> @mut Attr {
+ let local_name = if eq_slice(local_name, name) {
+ None
+ } else {
+ Some(local_name)
+ };
+ Attr::new_helper(window, name, value, local_name, namespace, prefix)
+ }
+
+ fn new_helper(window: &Window, name: ~str, value: ~str, local_name: Option<~str>,
+ namespace: Namespace, prefix: Option<~str>) -> @mut Attr {
+ let attr = Attr::new_inherited(name, value, local_name, namespace, prefix);
+ reflect_dom_object(@mut attr, window, AttrBinding::Wrap)
+ }
+
+ pub fn local_name<'a>(&'a self) -> &'a str {
+ match self.local_name {
+ Some(ref x) => x.as_slice(),
+ None => self.name.as_slice()
+ }
+ }
+
+ pub fn LocalName(&self) -> DOMString {
+ Some(self.local_name().to_owned())
+ }
+
+ pub fn Value(&self) -> DOMString {
+ Some(self.value.clone())
+ }
+
+ pub fn SetValue(&mut self, value: &DOMString) {
+ self.value = null_str_as_empty(value);
+ }
+
+ pub fn Name(&self) -> DOMString {
+ Some(self.name.clone())
+ }
+
+ pub fn GetNamespaceURI(&self) -> DOMString {
+ self.namespace.to_str()
+ }
+
+ pub fn GetPrefix(&self) -> DOMString {
+ self.prefix.clone()
+ }
+}
diff --git a/src/components/script/dom/bindings/codegen/Attr.webidl b/src/components/script/dom/bindings/codegen/Attr.webidl
new file mode 100644
index 00000000000..2b3d18150d8
--- /dev/null
+++ b/src/components/script/dom/bindings/codegen/Attr.webidl
@@ -0,0 +1,18 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://dom.spec.whatwg.org/#interface-attr
+ *
+ */
+
+interface Attr {
+ readonly attribute DOMString localName;
+ attribute DOMString value;
+
+ readonly attribute DOMString name;
+ readonly attribute DOMString? namespaceURI;
+ readonly attribute DOMString? prefix;
+};
diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf
index 6de264edc35..2c75ed85b8b 100644
--- a/src/components/script/dom/bindings/codegen/Bindings.conf
+++ b/src/components/script/dom/bindings/codegen/Bindings.conf
@@ -66,6 +66,9 @@
DOMInterfaces = {
+'Attr' : {
+},
+
'AudioBuffer' : {
},
@@ -178,7 +181,7 @@ DOMInterfaces = {
'Element': {
'nativeType': 'AbstractNode<ScriptView>',
'pointerType': '',
- 'needsAbstract': ['getClientRects', 'getBoundingClientRect', 'setAttribute']
+ 'needsAbstract': ['getClientRects', 'getBoundingClientRect', 'setAttribute', 'setAttributeNS', 'id']
},
'Event': {
diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs
index 716f16459d5..6fa2a8ec0c3 100644
--- a/src/components/script/dom/bindings/utils.rs
+++ b/src/components/script/dom/bindings/utils.rs
@@ -784,7 +784,8 @@ pub enum Error {
HierarchyRequest,
InvalidCharacter,
NotSupported,
- InvalidState
+ InvalidState,
+ NamespaceError
}
pub type Fallible<T> = Result<T, Error>;
@@ -883,7 +884,14 @@ pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
/// for details.
-pub fn is_valid_element_name(name: &str) -> bool {
+#[deriving(Eq)]
+pub enum XMLName {
+ QName,
+ Name,
+ InvalidXMLName
+}
+
+pub fn xml_name_type(name: &str) -> XMLName {
fn is_valid_start(c: char) -> bool {
match c {
':' |
@@ -919,20 +927,34 @@ pub fn is_valid_element_name(name: &str) -> bool {
}
let mut iter = name.iter();
+ let mut non_qname_colons = false;
+ let mut seen_colon = false;
match iter.next() {
- None => return false,
+ None => return InvalidXMLName,
Some(c) => {
if !is_valid_start(c) {
- return false;
+ return InvalidXMLName;
+ }
+ if c == ':' {
+ non_qname_colons = true;
}
}
}
for c in name.iter() {
if !is_valid_continuation(c) {
- return false;
+ return InvalidXMLName;
+ }
+ if c == ':' {
+ match seen_colon {
+ true => non_qname_colons = true,
+ false => seen_colon = true
+ }
}
}
- true
+ match non_qname_colons {
+ false => QName,
+ true => Name
+ }
}
diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs
index 9a978027b00..e7542fc8975 100644
--- a/src/components/script/dom/document.rs
+++ b/src/components/script/dom/document.rs
@@ -7,7 +7,7 @@ use dom::bindings::codegen::DocumentBinding;
use dom::bindings::utils::{Reflectable, Reflector, Traceable, reflect_dom_object};
use dom::bindings::utils::{ErrorResult, Fallible, NotSupported, InvalidCharacter};
use dom::bindings::utils::{DOMString, null_str_as_empty_ref, null_str_as_empty, null_str_as_word_null};
-use dom::bindings::utils::is_valid_element_name;
+use dom::bindings::utils::{xml_name_type, InvalidXMLName};
use dom::documentfragment::DocumentFragment;
use dom::element::{Element};
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
@@ -90,6 +90,7 @@ impl AbstractDocument {
}
}
+#[deriving(Eq)]
pub enum DocumentType {
HTML,
SVG,
@@ -203,7 +204,7 @@ impl Document {
pub fn CreateElement(&self, abstract_self: AbstractDocument, local_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
let local_name = null_str_as_empty(local_name);
- if !is_valid_element_name(local_name) {
+ if xml_name_type(local_name) == InvalidXMLName {
return Err(InvalidCharacter);
}
let local_name = local_name.to_ascii_lower();
diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs
index 1901278b40d..d0baf973bc9 100644
--- a/src/components/script/dom/element.rs
+++ b/src/components/script/dom/element.rs
@@ -5,12 +5,17 @@
//! Element nodes.
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
-use dom::bindings::utils::{null_str_as_empty, null_str_as_empty_ref};
+use dom::bindings::utils::{null_str_as_empty, null_str_as_empty_ref, NamespaceError};
+use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
+use dom::attr:: Attr;
+use dom::document;
+use dom::namespace;
+use dom::namespace::Namespace;
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use style;
@@ -18,12 +23,13 @@ use servo_util::tree::{TreeNodeRef, ElementLike};
use std::comm;
use std::hashmap::HashMap;
+use std::str::{eq, eq_slice};
use std::ascii::StrAsciiExt;
pub struct Element {
node: Node<ScriptView>,
tag_name: ~str, // TODO: This should be an atom, not a ~str.
- attrs: HashMap<~str, ~str>,
+ attrs: HashMap<~str, ~[@mut Attr]>,
attrs_list: ~[~str], // store an order of attributes.
style_attribute: Option<style::PropertyDeclarationBlock>,
}
@@ -120,18 +126,11 @@ impl ElementLike for Element {
self.tag_name.as_slice()
}
- fn get_attr<'a>(&'a self, name: &str) -> Option<&'a str> {
- // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
- let name = name.to_ascii_lower();
- let value: Option<&str> = self.attrs.find_equiv(&name).map(|value| {
- let value: &str = *value;
- value
- });
-
- return value;
+ fn get_attr(&self, name: &str) -> Option<~str> {
+ self.get_attribute(&None, name).map(|attr| attr.value.clone())
}
- fn get_link<'a>(&'a self) -> Option<&'a str> {
+ fn get_link(&self) -> Option<~str>{
// FIXME: This is HTML only.
match self.node.type_id {
// http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-link
@@ -155,28 +154,103 @@ impl<'self> Element {
}
}
+ pub fn normalize_attr_name(&self, name: &DOMString) -> ~str {
+ //FIXME: Throw for XML-invalid names
+ let owner = self.node.owner_doc();
+ if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
+ null_str_as_empty(name).to_ascii_lower()
+ } else {
+ null_str_as_empty(name)
+ }
+ }
+
+ pub fn get_attribute<'a>(&'a self,
+ namespace_url: &DOMString,
+ name: &str) -> Option<@mut Attr> {
+ let namespace = Namespace::from_str(namespace_url);
+ // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
+ let name = name.to_ascii_lower();
+ self.attrs.find_equiv(&name).and_then(|attrs| {
+ do attrs.iter().find |attr| {
+ eq_slice(attr.local_name(), name) && attr.namespace == namespace
+ }.map(|x| *x)
+ })
+ }
+
pub fn set_attr(&mut self,
abstract_self: AbstractNode<ScriptView>,
raw_name: &DOMString,
- raw_value: &DOMString) {
+ raw_value: &DOMString) -> ErrorResult {
+ self.set_attribute(abstract_self, namespace::Null, raw_name, raw_value)
+ }
+
+ pub fn set_attribute(&mut self,
+ abstract_self: AbstractNode<ScriptView>,
+ namespace: Namespace,
+ raw_name: &DOMString,
+ raw_value: &DOMString) -> ErrorResult {
+ //FIXME: Throw for XML-invalid names
+ //FIXME: Throw for XMLNS-invalid names
let name = null_str_as_empty(raw_name).to_ascii_lower();
let value = null_str_as_empty(raw_value);
+ let (prefix, local_name) = if name.contains(":") {
+ let parts: ~[&str] = name.splitn_iter(':', 1).collect();
+ (Some(parts[0].to_owned()), parts[1].to_owned())
+ } else {
+ (None, name.clone())
+ };
+ match prefix {
+ Some(ref prefix_str) => {
+ if (namespace == namespace::Null ||
+ (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
+ (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
+ return Err(NamespaceError);
+ }
+ },
+ None => {}
+ }
// FIXME: reduce the time of `value.clone()`.
- self.attrs.mangle(name.clone(), value.clone(),
- |new_name: &~str, new_value: ~str| {
+ let win = self.node.owner_doc().document().window;
+ let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
+ name.clone(), namespace.clone(), prefix);
+ self.attrs.mangle(local_name.clone(), new_attr,
+ |new_name: &~str, new_value: @mut Attr| {
// register to the ordered list.
self.attrs_list.push(new_name.clone());
- new_value
+ ~[new_value]
},
- |_, old_value: &mut ~str, new_value: ~str| {
+ |name, old_value: &mut ~[@mut Attr], new_value: @mut Attr| {
// update value.
- *old_value = new_value;
+ let mut found = false;
+ for attr in old_value.mut_iter() {
+ if eq_slice(attr.local_name(), *name) &&
+ attr.namespace == new_value.namespace {
+ *attr = new_value;
+ found = true;
+ break;
+ }
+
+ }
+ if !found {
+ old_value.push(new_value);
+ self.attrs_list.push(name.clone());
+ }
});
- if "style" == name {
- self.style_attribute = Some(style::parse_style_attribute(
- null_str_as_empty_ref(raw_value)));
+ self.after_set_attr(abstract_self, &namespace, local_name, raw_value);
+ Ok(())
+ }
+
+ fn after_set_attr(&mut self,
+ abstract_self: AbstractNode<ScriptView>,
+ namespace: &Namespace,
+ local_name: ~str,
+ value: &DOMString) {
+
+ if "style" == local_name && *namespace == namespace::Null {
+ self.style_attribute = Some(style::parse_style_attribute(
+ null_str_as_empty_ref(value)));
}
// TODO: update owner document's id hashmap for `document.getElementById()`
@@ -187,12 +261,12 @@ impl<'self> Element {
match abstract_self.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => {
do abstract_self.with_mut_image_element |image| {
- image.AfterSetAttr(raw_name, raw_value);
+ image.AfterSetAttr(&Some(local_name.clone()), value);
}
}
ElementNodeTypeId(HTMLIframeElementTypeId) => {
do abstract_self.with_mut_iframe_element |iframe| {
- iframe.AfterSetAttr(raw_name, raw_value);
+ iframe.AfterSetAttr(&Some(local_name.clone()), value);
}
}
_ => ()
@@ -210,19 +284,24 @@ impl Element {
Some(self.tag_name.to_owned().to_ascii_upper())
}
- pub fn Id(&self) -> DOMString {
- None
+ pub fn Id(&self, _abstract_self: AbstractNode<ScriptView>) -> DOMString {
+ match self.get_attr(&"id") {
+ Some(x) => Some(x),
+ None => Some(~"")
+ }
}
- pub fn SetId(&self, _id: &DOMString) {
+ pub fn SetId(&mut self, abstract_self: AbstractNode<ScriptView>, id: &DOMString) {
+ self.set_attribute(abstract_self, namespace::Null, &Some(~"id"), id);
}
pub fn GetAttribute(&self, name: &DOMString) -> DOMString {
- self.get_attr(null_str_as_empty_ref(name)).map(|s| s.to_owned())
+ self.get_attr(null_str_as_empty_ref(name))
}
- pub fn GetAttributeNS(&self, _namespace: &DOMString, _localname: &DOMString) -> DOMString {
- None
+ pub fn GetAttributeNS(&self, namespace: &DOMString, local_name: &DOMString) -> DOMString {
+ self.get_attribute(namespace, null_str_as_empty_ref(local_name))
+ .map(|attr| attr.value.clone())
}
pub fn SetAttribute(&mut self,
@@ -233,8 +312,20 @@ impl Element {
Ok(())
}
- pub fn SetAttributeNS(&self, _namespace: &DOMString, _localname: &DOMString, _value: &DOMString) -> ErrorResult {
- Ok(())
+ pub fn SetAttributeNS(&mut self,
+ abstract_self: AbstractNode<ScriptView>,
+ namespace_url: &DOMString,
+ name: &DOMString,
+ value: &DOMString) -> ErrorResult {
+ let name_type = xml_name_type(name.to_str());
+ match name_type {
+ InvalidXMLName => return Err(InvalidCharacter),
+ Name => return Err(NamespaceError),
+ QName => {}
+ }
+
+ let namespace = Namespace::from_str(namespace_url);
+ self.set_attribute(abstract_self, namespace, name, value)
}
pub fn RemoveAttribute(&self, _name: &DOMString) -> ErrorResult {
@@ -245,12 +336,12 @@ impl Element {
Ok(())
}
- pub fn HasAttribute(&self, _name: &DOMString) -> bool {
- false
+ pub fn HasAttribute(&self, name: &DOMString) -> bool {
+ self.GetAttribute(name).is_some()
}
- pub fn HasAttributeNS(&self, _nameapce: &DOMString, _localname: &DOMString) -> bool {
- false
+ pub fn HasAttributeNS(&self, namespace: &DOMString, local_name: &DOMString) -> bool {
+ self.GetAttributeNS(namespace, local_name).is_some()
}
pub fn GetElementsByTagName(&self, _localname: &DOMString) -> @mut HTMLCollection {
@@ -385,17 +476,3 @@ impl Element {
Ok(None)
}
}
-
-pub struct Attr {
- name: ~str,
- value: ~str,
-}
-
-impl Attr {
- pub fn new(name: ~str, value: ~str) -> Attr {
- Attr {
- name: name,
- value: value
- }
- }
-}
diff --git a/src/components/script/dom/namespace.rs b/src/components/script/dom/namespace.rs
new file mode 100644
index 00000000000..7fe8e68e232
--- /dev/null
+++ b/src/components/script/dom/namespace.rs
@@ -0,0 +1,44 @@
+/* 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::utils::{DOMString, null_str_as_empty_ref};
+
+#[deriving(Eq, Clone)]
+pub enum Namespace {
+ Null,
+ HTML,
+ XML,
+ XMLNS,
+ XLink,
+ SVG,
+ MathML,
+ Other(~str)
+}
+
+impl Namespace {
+ pub fn from_str(url: &DOMString) -> Namespace {
+ match null_str_as_empty_ref(url) {
+ &"http://www.w3.org/1999/xhtml" => HTML,
+ &"http://www.w3.org/XML/1998/namespace" => XML,
+ &"http://www.w3.org/2000/xmlns/" => XMLNS,
+ &"http://www.w3.org/1999/xlink" => XLink,
+ &"http://www.w3.org/2000/svg" => SVG,
+ &"http://www.w3.org/1998/Math/MathML" => MathML,
+ &"" => Null,
+ ns => Other(ns.to_owned())
+ }
+ }
+ pub fn to_str(&self) -> DOMString {
+ match *self {
+ Null => None,
+ HTML => Some(~"http://www.w3.org/1999/xhtml"),
+ XML => Some(~"http://www.w3.org/XML/1998/namespace"),
+ XMLNS => Some(~"http://www.w3.org/2000/xmlns/"),
+ XLink => Some(~"http://www.w3.org/1999/xlink"),
+ SVG => Some(~"http://www.w3.org/2000/svg"),
+ MathML => Some(~"http://www.w3.org/1998/Math/MathML"),
+ Other(ref x) => Some(x.to_owned())
+ }
+ }
+}
diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs
index 07f5fb7f0df..44e06eb14fc 100644
--- a/src/components/script/html/hubbub_html_parser.rs
+++ b/src/components/script/html/hubbub_html_parser.rs
@@ -8,6 +8,7 @@ use dom::htmlelement::HTMLElement;
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
use dom::htmliframeelement::IFrameSize;
use dom::htmlformelement::HTMLFormElement;
+use dom::namespace;
use dom::node::{AbstractNode, ElementNodeTypeId, ScriptView};
use dom::types::*;
use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
@@ -339,7 +340,10 @@ pub fn parse_html(cx: *JSContext,
debug!("-- attach attrs");
do node.as_mut_element |element| {
for attr in tag.attributes.iter() {
- element.set_attr(node, &Some(attr.name.clone()), &Some(attr.value.clone()));
+ element.set_attribute(node,
+ namespace::Null,
+ &Some(attr.name.clone()),
+ &Some(attr.value.clone()));
}
}
@@ -350,7 +354,7 @@ pub fn parse_html(cx: *JSContext,
do node.with_imm_element |element| {
match (element.get_attr("rel"), element.get_attr("href")) {
(Some(rel), Some(href)) => {
- if rel == "stylesheet" {
+ if "stylesheet" == rel {
debug!("found CSS stylesheet: {:s}", href);
let url = make_url(href.to_str(), Some(url2.clone()));
css_chan2.send(CSSTaskNewFile(UrlProvenance(url)));
diff --git a/src/components/script/script.rc b/src/components/script/script.rc
index 0307e70b580..a2617f0a9a3 100644
--- a/src/components/script/script.rc
+++ b/src/components/script/script.rc
@@ -44,6 +44,7 @@ pub mod dom {
pub use super::bindings::codegen::InterfaceTypes::*;
}
+ pub mod attr;
pub mod blob;
pub mod characterdata;
pub mod clientrect;
@@ -130,6 +131,7 @@ pub mod dom {
pub mod htmlvideoelement;
pub mod htmlunknownelement;
pub mod mouseevent;
+ pub mod namespace;
pub mod navigator;
pub mod node;
pub mod nodelist;
diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs
index 7e93387f83b..94ebb4fd28a 100644
--- a/src/components/style/selector_matching.rs
+++ b/src/components/style/selector_matching.rs
@@ -12,6 +12,7 @@ use media_queries::{Device, Screen};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike};
+use std::str;
pub enum StylesheetOrigin {
UserAgentOrigin,
@@ -207,7 +208,10 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
// TODO: cache and intern IDs on elements.
IDSelector(ref id) => {
do element.with_imm_element_like |element: &E| {
- element.get_attr("id") == Some(id.as_slice())
+ match element.get_attr("id") {
+ Some(attr) => str::eq_slice(attr, *id),
+ None => false
+ }
}
}
// TODO: cache and intern classe names on elements.
diff --git a/src/components/util/tree.rs b/src/components/util/tree.rs
index 4a156cfa6ca..c84de349579 100644
--- a/src/components/util/tree.rs
+++ b/src/components/util/tree.rs
@@ -348,6 +348,6 @@ pub trait TreeNode<Ref: TreeNodeRef<Self>> {
pub trait ElementLike {
fn get_local_name<'a>(&'a self) -> &'a str;
- fn get_attr<'a>(&'a self, name: &str) -> Option<&'a str>;
- fn get_link<'a>(&'a self) -> Option<&'a str>;
+ fn get_attr(&self, name: &str) -> Option<~str>;
+ fn get_link(&self) -> Option<~str>;
}