Skip to content

Commit

Permalink
auto merge of #2616 : Ms2ger/servo/attrvalue, r=jdm
Browse files Browse the repository at this point in the history
Obsoletes #2073.
  • Loading branch information
bors-servo committed Jun 13, 2014
2 parents 58b776e + b012c99 commit da668f5
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 47 deletions.
59 changes: 50 additions & 9 deletions src/components/script/dom/attr.rs
Expand Up @@ -6,25 +6,59 @@ 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 {
FirstSetAttr,
ReplacedAttr,
}

#[deriving(Eq, Clone, Encodable)]
pub enum AttrValue {
StringAttrValue(DOMString),
TokenListAttrValue(DOMString, Vec<(uint, uint)>),
UIntAttrValue(DOMString, u32),
}

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 from_u32(string: DOMString, default: u32) -> AttrValue {
let result: u32 = from_str(string.as_slice()).unwrap_or(default);
UIntAttrValue(string, result)
}

pub fn as_slice<'a>(&'a self) -> &'a str {
match *self {
StringAttrValue(ref value) |
TokenListAttrValue(ref value, _) |
UIntAttrValue(ref value, _) => value.as_slice(),
}
}
}

#[deriving(Encodable)]
pub struct Attr {
pub reflector_: Reflector,
pub local_name: DOMString,
pub value: DOMString,
value: AttrValue,
pub name: DOMString,
pub namespace: Namespace,
pub prefix: Option<DOMString>,
Expand All @@ -44,7 +78,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 {
Expand All @@ -58,22 +92,22 @@ 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;

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 => {}
Expand All @@ -82,10 +116,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()
}
Expand All @@ -106,10 +144,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);
}

Expand Down
1 change: 1 addition & 0 deletions src/components/script/dom/bindings/codegen/Bindings.conf
Expand Up @@ -32,6 +32,7 @@ DOMInterfaces = {
'DOMException': {},
'DOMImplementation': {},
'DOMParser': {},
'DOMTokenList': {},
'Element': {},
'Event': {},
'EventHandler': {},
Expand Down
103 changes: 103 additions & 0 deletions src/components/script/dom/domtokenlist.rs
@@ -0,0 +1,103 @@
/* 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::attr::{Attr, TokenListAttrValue};
use dom::bindings::codegen::Bindings::DOMTokenListBinding;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable};
use dom::bindings::utils::{Reflector, Reflectable, reflect_dom_object};
use dom::element::{Element, AttributeHandlers};
use dom::node::window_from_node;

use servo_util::namespace::Null;
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct DOMTokenList {
reflector_: Reflector,
element: JS<Element>,
local_name: &'static str,
}

impl DOMTokenList {
pub fn new_inherited(element: &JSRef<Element>,
local_name: &'static str) -> DOMTokenList {
DOMTokenList {
reflector_: Reflector::new(),
element: JS::from_rooted(element.clone()),
local_name: local_name,
}
}

pub fn new(element: &JSRef<Element>,
local_name: &'static str) -> Temporary<DOMTokenList> {
let window = window_from_node(element).root();
reflect_dom_object(box DOMTokenList::new_inherited(element, local_name),
&*window, DOMTokenListBinding::Wrap)
}
}

impl Reflectable for DOMTokenList {
fn reflector<'a>(&'a self) -> &'a Reflector {
&self.reflector_
}

fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
&mut self.reflector_
}
}

trait PrivateDOMTokenListHelpers {
fn attribute(&self) -> Option<Temporary<Attr>>;
}

impl<'a> PrivateDOMTokenListHelpers for JSRef<'a, DOMTokenList> {
fn attribute(&self) -> Option<Temporary<Attr>> {
let element = self.element.root();
element.deref().get_attribute(Null, self.local_name)
}
}

pub trait DOMTokenListMethods {
fn Length(&self) -> u32;
fn Item(&self, index: u32) -> Option<DOMString>;
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<DOMString>;
}

// http://dom.spec.whatwg.org/#domtokenlist
impl<'a> DOMTokenListMethods for JSRef<'a, DOMTokenList> {
// http://dom.spec.whatwg.org/#dom-domtokenlist-length
fn Length(&self) -> u32 {
let attribute = self.attribute().root();
match attribute {
Some(attribute) => {
match *attribute.deref().value() {
TokenListAttrValue(_, ref indexes) => indexes.len() as u32,
_ => fail!("Expected a TokenListAttrValue"),
}
}
None => 0,
}
}

// http://dom.spec.whatwg.org/#dom-domtokenlist-item
fn Item(&self, index: u32) -> Option<DOMString> {
let attribute = self.attribute().root();
attribute.and_then(|attribute| {
match *attribute.deref().value() {
TokenListAttrValue(ref value, ref indexes) => {
indexes.as_slice().get(index as uint).map(|&(start, end)| {
value.as_slice().slice(start, end).to_string()
})
},
_ => fail!("Expected a TokenListAttrValue"),
}
})
}

fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<DOMString> {
let item = self.Item(index);
*found = item.is_some();
item
}
}

0 comments on commit da668f5

Please sign in to comment.