diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/script/dom/attr.rs | 52 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 43 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/virtualmethods.rs | 10 |
4 files changed, 90 insertions, 17 deletions
diff --git a/src/components/script/dom/attr.rs b/src/components/script/dom/attr.rs index 7d75c281e01..f31a281b36d 100644 --- a/src/components/script/dom/attr.rs +++ b/src/components/script/dom/attr.rs @@ -6,13 +6,13 @@ use dom::bindings::codegen::Bindings::AttrBinding; use dom::bindings::codegen::InheritTypes::NodeCast; use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; -use dom::element::Element; +use dom::element::{Element, AttributeHandlers}; use dom::node::Node; use dom::window::Window; use dom::virtualmethods::vtable_for; use servo_util::namespace; use servo_util::namespace::Namespace; -use servo_util::str::DOMString; +use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; use std::cell::Cell; pub enum AttrSettingType { @@ -20,11 +20,38 @@ pub enum AttrSettingType { ReplacedAttr, } +#[deriving(Eq, Clone, Encodable)] +pub enum AttrValue { + StringAttrValue(DOMString), + TokenListAttrValue(DOMString, Vec<(uint, uint)>), +} + +impl AttrValue { + pub fn from_tokenlist(list: DOMString) -> AttrValue { + let mut indexes = vec![]; + let mut last_index: uint = 0; + for (index, ch) in list.as_slice().char_indices() { + if HTML_SPACE_CHARACTERS.iter().any(|&space| space == ch) { + indexes.push((last_index, index)); + last_index = index + 1; + } + } + return TokenListAttrValue(list, indexes); + } + + pub fn as_slice<'a>(&'a self) -> &'a str { + match *self { + StringAttrValue(ref value) | + TokenListAttrValue(ref value, _) => value.as_slice(), + } + } +} + #[deriving(Encodable)] pub struct Attr { pub reflector_: Reflector, pub local_name: DOMString, - value: DOMString, + value: AttrValue, pub name: DOMString, pub namespace: Namespace, pub prefix: Option<DOMString>, @@ -44,7 +71,7 @@ impl Reflectable for Attr { } impl Attr { - fn new_inherited(local_name: DOMString, value: DOMString, + fn new_inherited(local_name: DOMString, value: AttrValue, name: DOMString, namespace: Namespace, prefix: Option<DOMString>, owner: &JSRef<Element>) -> Attr { Attr { @@ -58,14 +85,14 @@ impl Attr { } } - pub fn new(window: &JSRef<Window>, local_name: DOMString, value: DOMString, + pub fn new(window: &JSRef<Window>, local_name: DOMString, value: AttrValue, name: DOMString, namespace: Namespace, prefix: Option<DOMString>, owner: &JSRef<Element>) -> Temporary<Attr> { let attr = Attr::new_inherited(local_name, value, name, namespace, prefix, owner); reflect_dom_object(box attr, window, AttrBinding::Wrap) } - pub fn set_value(&mut self, set_type: AttrSettingType, value: DOMString) { + pub fn set_value(&mut self, set_type: AttrSettingType, value: AttrValue) { let owner = self.owner.get().root(); let node: &JSRef<Node> = NodeCast::from_ref(&*owner); let namespace_is_null = self.namespace == namespace::Null; @@ -73,7 +100,7 @@ impl Attr { match set_type { ReplacedAttr => { if namespace_is_null { - vtable_for(node).before_remove_attr(self.local_name.clone(), self.value.clone()); + vtable_for(node).before_remove_attr(self.local_name.clone(), self.value.as_slice().to_string()); } } FirstSetAttr => {} @@ -82,10 +109,14 @@ impl Attr { self.value = value; if namespace_is_null { - vtable_for(node).after_set_attr(self.local_name.clone(), self.value.clone()); + vtable_for(node).after_set_attr(self.local_name.clone(), self.value.as_slice().to_string()); } } + pub fn value<'a>(&'a self) -> &'a AttrValue { + &self.value + } + pub fn value_ref<'a>(&'a self) -> &'a str { self.value.as_slice() } @@ -106,10 +137,13 @@ impl<'a> AttrMethods for JSRef<'a, Attr> { } fn Value(&self) -> DOMString { - self.value.clone() + self.value.as_slice().to_string() } fn SetValue(&mut self, value: DOMString) { + let owner = self.owner.get().root(); + let value = owner.deref().parse_attribute( + &self.namespace, self.deref().local_name.as_slice(), value); self.set_value(ReplacedAttr, value); } diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index aa1873a04de..c346f6f2cf9 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -5,6 +5,7 @@ //! Element nodes. use dom::attr::{Attr, ReplacedAttr, FirstSetAttr, AttrMethods}; +use dom::attr::{AttrValue, StringAttrValue}; use dom::attrlist::AttrList; use dom::bindings::codegen::Bindings::ElementBinding; use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast}; @@ -222,10 +223,12 @@ pub trait AttributeHandlers { fn set_attribute_from_parser(&self, local_name: DOMString, value: DOMString, namespace: Namespace, prefix: Option<DOMString>); - fn set_attribute(&self, name: &str, value: DOMString); - fn do_set_attribute(&self, local_name: DOMString, value: DOMString, + fn set_attribute(&self, name: &str, value: AttrValue); + fn do_set_attribute(&self, local_name: DOMString, value: AttrValue, name: DOMString, namespace: Namespace, prefix: Option<DOMString>, cb: |&JSRef<Attr>| -> bool); + fn parse_attribute(&self, namespace: &Namespace, local_name: &str, + value: DOMString) -> AttrValue; fn remove_attribute(&self, namespace: Namespace, name: DOMString) -> ErrorResult; fn notify_attribute_changed(&self, local_name: DOMString); @@ -236,6 +239,7 @@ pub trait AttributeHandlers { fn set_url_attribute(&self, name: &str, value: DOMString); fn get_string_attribute(&self, name: &str) -> DOMString; fn set_string_attribute(&self, name: &str, value: DOMString); + fn set_tokenlist_attribute(&self, name: &str, value: DOMString); fn set_uint_attribute(&self, name: &str, value: u32); } @@ -262,10 +266,11 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { None => local_name.clone(), Some(ref prefix) => format!("{:s}:{:s}", *prefix, local_name), }; + let value = self.parse_attribute(&namespace, local_name.as_slice(), value); self.do_set_attribute(local_name, value, name, namespace, prefix, |_| false) } - fn set_attribute(&self, name: &str, value: DOMString) { + fn set_attribute(&self, name: &str, value: AttrValue) { assert!(name == name.to_ascii_lower().as_slice()); assert!(!name.contains(":")); @@ -277,7 +282,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { |attr| attr.deref().local_name.as_slice() == name); } - fn do_set_attribute(&self, local_name: DOMString, value: DOMString, + fn do_set_attribute(&self, local_name: DOMString, value: AttrValue, name: DOMString, namespace: Namespace, prefix: Option<DOMString>, cb: |&JSRef<Attr>| -> bool) { let idx = self.deref().attrs.borrow().iter() @@ -297,6 +302,16 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.deref().attrs.borrow().get(idx).root().set_value(set_type, value); } + fn parse_attribute(&self, namespace: &Namespace, local_name: &str, + value: DOMString) -> AttrValue { + if *namespace == namespace::Null { + vtable_for(NodeCast::from_ref(self)) + .parse_plain_attribute(local_name, value) + } else { + StringAttrValue(value) + } + } + fn remove_attribute(&self, namespace: Namespace, name: DOMString) -> ErrorResult { let (_, local_name) = get_attribute_parts(name.clone()); @@ -362,12 +377,17 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { } fn set_string_attribute(&self, name: &str, value: DOMString) { assert!(name == name.to_ascii_lower().as_slice()); - self.set_attribute(name, value); + self.set_attribute(name, StringAttrValue(value)); + } + + fn set_tokenlist_attribute(&self, name: &str, value: DOMString) { + assert!(name == name.to_ascii_lower().as_slice()); + self.set_attribute(name, AttrValue::from_tokenlist(value)); } fn set_uint_attribute(&self, name: &str, value: u32) { assert!(name == name.to_ascii_lower().as_slice()); - self.set_attribute(name, value.to_str()); + self.set_attribute(name, StringAttrValue(value.to_str())); } } @@ -462,7 +482,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-classname fn SetClassName(&self, class: DOMString) { - self.set_string_attribute("class", class); + self.set_tokenlist_attribute("class", class); } // http://dom.spec.whatwg.org/#dom-element-attributes @@ -525,6 +545,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { }; // Step 3-5. + let value = self.parse_attribute(&namespace::Null, name.as_slice(), value); self.do_set_attribute(name.clone(), value, name.clone(), namespace::Null, None, |attr| { attr.deref().name == name }); @@ -586,6 +607,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } // Step 9. + let value = self.parse_attribute(&namespace, local_name.as_slice(), value); self.do_set_attribute(local_name.clone(), value, name, namespace.clone(), prefix, |attr| { attr.deref().local_name == local_name && attr.deref().namespace == namespace @@ -771,6 +793,13 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { self.notify_attribute_changed(name); } + fn parse_plain_attribute(&self, name: &str, value: DOMString) -> AttrValue { + match name { + "class" => AttrValue::from_tokenlist(value), + _ => self.super_type().unwrap().parse_plain_attribute(name, value), + } + } + fn bind_to_tree(&self) { match self.super_type() { Some(ref s) => s.bind_to_tree(), diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 91e666d1e61..87b43e7269a 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -1300,7 +1300,7 @@ impl Node { for attr in node_elem.attrs.borrow().iter().map(|attr| attr.root()) { copy_elem.attrs.borrow_mut().push_unrooted( &Attr::new(&*window, - attr.deref().local_name.clone(), attr.deref().value_ref().to_string(), + attr.deref().local_name.clone(), attr.deref().value().clone(), attr.deref().name.clone(), attr.deref().namespace.clone(), attr.deref().prefix.clone(), ©_elem_alias)); } diff --git a/src/components/script/dom/virtualmethods.rs b/src/components/script/dom/virtualmethods.rs index aafe3efe4f4..b32af5139da 100644 --- a/src/components/script/dom/virtualmethods.rs +++ b/src/components/script/dom/virtualmethods.rs @@ -2,6 +2,7 @@ * 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::attr::{AttrValue, StringAttrValue}; use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast; use dom::bindings::codegen::InheritTypes::HTMLBodyElementCast; @@ -50,6 +51,15 @@ pub trait VirtualMethods { } } + /// Returns the right AttrValue variant for the attribute with name `name` + /// on this element. + fn parse_plain_attribute(&self, name: &str, value: DOMString) -> AttrValue { + match self.super_type() { + Some(ref s) => s.parse_plain_attribute(name, value), + _ => StringAttrValue(value), + } + } + /// Called when a Node is appended to a tree that is part of a Document. fn bind_to_tree(&self) { match self.super_type() { |