aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/attr.rs')
-rw-r--r--components/script/dom/attr.rs200
1 files changed, 200 insertions, 0 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
new file mode 100644
index 00000000000..9f3fc9dc96e
--- /dev/null
+++ b/components/script/dom/attr.rs
@@ -0,0 +1,200 @@
+/* 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::AttrBinding;
+use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
+use dom::bindings::codegen::InheritTypes::NodeCast;
+use dom::bindings::global::Window;
+use dom::bindings::js::{JS, JSRef, Temporary};
+use dom::bindings::trace::Traceable;
+use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
+use dom::element::{Element, AttributeHandlers};
+use dom::node::Node;
+use dom::window::Window;
+use dom::virtualmethods::vtable_for;
+use servo_util::atom::Atom;
+use servo_util::namespace;
+use servo_util::namespace::Namespace;
+use servo_util::str::{DOMString, split_html_space_chars};
+use std::cell::{Ref, RefCell};
+use std::mem;
+use std::slice::Items;
+
+pub enum AttrSettingType {
+ FirstSetAttr,
+ ReplacedAttr,
+}
+
+#[deriving(PartialEq, Clone, Encodable)]
+pub enum AttrValue {
+ StringAttrValue(DOMString),
+ TokenListAttrValue(DOMString, Vec<Atom>),
+ UIntAttrValue(DOMString, u32),
+ AtomAttrValue(Atom),
+}
+
+impl AttrValue {
+ pub fn from_tokenlist(tokens: DOMString) -> AttrValue {
+ let atoms = split_html_space_chars(tokens.as_slice())
+ .map(|token| Atom::from_slice(token)).collect();
+ TokenListAttrValue(tokens, atoms)
+ }
+
+ pub fn from_u32(string: DOMString, default: u32) -> AttrValue {
+ let result: u32 = from_str(string.as_slice()).unwrap_or(default);
+ UIntAttrValue(string, result)
+ }
+
+ pub fn from_atomic(string: DOMString) -> AttrValue {
+ let value = Atom::from_slice(string.as_slice());
+ AtomAttrValue(value)
+ }
+
+ pub fn tokens<'a>(&'a self) -> Option<Items<'a, Atom>> {
+ match *self {
+ TokenListAttrValue(_, ref tokens) => Some(tokens.iter()),
+ _ => None
+ }
+ }
+}
+
+impl Str for AttrValue {
+ fn as_slice<'a>(&'a self) -> &'a str {
+ match *self {
+ StringAttrValue(ref value) |
+ TokenListAttrValue(ref value, _) |
+ UIntAttrValue(ref value, _) => value.as_slice(),
+ AtomAttrValue(ref value) => value.as_slice(),
+ }
+ }
+}
+
+#[deriving(Encodable)]
+pub struct Attr {
+ reflector_: Reflector,
+ local_name: Atom,
+ value: Traceable<RefCell<AttrValue>>,
+ pub name: Atom,
+ pub namespace: Namespace,
+ pub prefix: Option<DOMString>,
+
+ /// the element that owns this attribute.
+ owner: JS<Element>,
+}
+
+impl Reflectable for Attr {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ &self.reflector_
+ }
+}
+
+impl Attr {
+ fn new_inherited(local_name: Atom, value: AttrValue,
+ name: Atom, namespace: Namespace,
+ prefix: Option<DOMString>, owner: &JSRef<Element>) -> Attr {
+ Attr {
+ reflector_: Reflector::new(),
+ local_name: local_name,
+ value: Traceable::new(RefCell::new(value)),
+ name: name,
+ namespace: namespace,
+ prefix: prefix,
+ owner: JS::from_rooted(owner),
+ }
+ }
+
+ pub fn new(window: &JSRef<Window>, local_name: Atom, value: AttrValue,
+ name: Atom, 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(*window), AttrBinding::Wrap)
+ }
+
+ pub fn set_value(&self, set_type: AttrSettingType, value: AttrValue) {
+ let owner = self.owner.root();
+ let node: &JSRef<Node> = NodeCast::from_ref(&*owner);
+ let namespace_is_null = self.namespace == namespace::Null;
+
+ match set_type {
+ ReplacedAttr => {
+ if namespace_is_null {
+ vtable_for(node).before_remove_attr(
+ self.local_name(),
+ self.value().as_slice().to_string())
+ }
+ }
+ FirstSetAttr => {}
+ }
+
+ *self.value.deref().borrow_mut() = value;
+
+ if namespace_is_null {
+ vtable_for(node).after_set_attr(
+ self.local_name(),
+ self.value().as_slice().to_string())
+ }
+ }
+
+ pub fn value<'a>(&'a self) -> Ref<'a, AttrValue> {
+ self.value.deref().borrow()
+ }
+
+ pub fn local_name<'a>(&'a self) -> &'a Atom {
+ &self.local_name
+ }
+}
+
+impl<'a> AttrMethods for JSRef<'a, Attr> {
+ fn LocalName(&self) -> DOMString {
+ self.local_name().as_slice().to_string()
+ }
+
+ fn Value(&self) -> DOMString {
+ self.value().as_slice().to_string()
+ }
+
+ fn SetValue(&self, value: DOMString) {
+ let owner = self.owner.root();
+ let value = owner.deref().parse_attribute(
+ &self.namespace, self.local_name(), value);
+ self.set_value(ReplacedAttr, value);
+ }
+
+ fn Name(&self) -> DOMString {
+ self.name.as_slice().to_string()
+ }
+
+ fn GetNamespaceURI(&self) -> Option<DOMString> {
+ match self.namespace.to_str() {
+ "" => None,
+ url => Some(url.to_string()),
+ }
+ }
+
+ fn GetPrefix(&self) -> Option<DOMString> {
+ self.prefix.clone()
+ }
+}
+
+pub trait AttrHelpersForLayout {
+ unsafe fn value_ref_forever(&self) -> &'static str;
+ unsafe fn value_atom_forever(&self) -> Option<Atom>;
+}
+
+impl AttrHelpersForLayout for Attr {
+ unsafe fn value_ref_forever(&self) -> &'static str {
+ // cast to point to T in RefCell<T> directly
+ let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref());
+ value.as_slice()
+ }
+
+ unsafe fn value_atom_forever(&self) -> Option<Atom> {
+ // cast to point to T in RefCell<T> directly
+ let value = mem::transmute::<&RefCell<AttrValue>, &AttrValue>(self.value.deref());
+ match *value {
+ AtomAttrValue(ref val) => Some(val.clone()),
+ _ => None,
+ }
+ }
+}