diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/domstringmap.rs | 37 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 57 | ||||
-rw-r--r-- | components/script/dom/webidls/DOMStringMap.webidl | 1 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLElement.webidl | 2 |
4 files changed, 79 insertions, 18 deletions
diff --git a/components/script/dom/domstringmap.rs b/components/script/dom/domstringmap.rs index 26218445c80..ff4990eb5f6 100644 --- a/components/script/dom/domstringmap.rs +++ b/components/script/dom/domstringmap.rs @@ -2,51 +2,56 @@ * 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::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DOMStringMapBinding; use dom::bindings::codegen::Bindings::DOMStringMapBinding::DOMStringMapMethods; +use dom::bindings::error::ErrorResult; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; +use dom::node::window_from_node; +use dom::htmlelement::{HTMLElement, HTMLElementCustomAttributeHelpers}; use servo_util::str::DOMString; -use std::collections::HashMap; - #[dom_struct] pub struct DOMStringMap { - map: DOMRefCell<HashMap<DOMString, DOMString>>, reflector_: Reflector, + element: JS<HTMLElement>, } impl DOMStringMap { - fn new_inherited() -> DOMStringMap { + fn new_inherited(element: JSRef<HTMLElement>) -> DOMStringMap { DOMStringMap { - map: DOMRefCell::new(HashMap::new()), reflector_: Reflector::new(), + element: JS::from_rooted(element), } } - pub fn new(global: GlobalRef) -> Temporary<DOMStringMap> { - reflect_dom_object(box DOMStringMap::new_inherited(), - global, DOMStringMapBinding::Wrap) + pub fn new(element: JSRef<HTMLElement>) -> Temporary<DOMStringMap> { + let window = window_from_node(element).root(); + reflect_dom_object(box DOMStringMap::new_inherited(element), + GlobalRef::Window(window.root_ref()), DOMStringMapBinding::Wrap) } } +// https://html.spec.whatwg.org/#domstringmap impl<'a> DOMStringMapMethods for JSRef<'a, DOMStringMap> { - fn NamedCreator(self, name: DOMString, value: DOMString) { - self.map.borrow_mut().insert(name, value); + fn NamedCreator(self, name: DOMString, value: DOMString) -> ErrorResult { + self.NamedSetter(name, value) } fn NamedDeleter(self, name: DOMString) { - self.map.borrow_mut().remove(&name); + let element = self.element.root(); + element.delete_custom_attr(name) } - fn NamedSetter(self, name: DOMString, value: DOMString) { - self.map.borrow_mut().insert(name, value); + fn NamedSetter(self, name: DOMString, value: DOMString) -> ErrorResult { + let element = self.element.root(); + element.set_custom_attr(name, value) } fn NamedGetter(self, name: DOMString, found: &mut bool) -> DOMString { - match self.map.borrow().get(&name) { + let element = self.element.root(); + match element.get_custom_attr(name) { Some(value) => { *found = true; value.clone() diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index e38ab5ff523..f36e84a078e 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -13,10 +13,13 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDeriv use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived}; use dom::bindings::js::{JSRef, Temporary, MutNullableJS}; +use dom::bindings::error::ErrorResult; +use dom::bindings::error::Error::Syntax; use dom::bindings::utils::{Reflectable, Reflector}; use dom::cssstyledeclaration::CSSStyleDeclaration; use dom::document::Document; -use dom::element::{Element, ElementTypeId, ActivationElementHelpers}; +use dom::domstringmap::DOMStringMap; +use dom::element::{Element, ElementTypeId, ActivationElementHelpers, AttributeHandlers}; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::node::{Node, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; @@ -31,6 +34,7 @@ use std::default::Default; pub struct HTMLElement { element: Element, style_decl: MutNullableJS<CSSStyleDeclaration>, + dataset: MutNullableJS<DOMStringMap>, } impl HTMLElementDerived for EventTarget { @@ -48,6 +52,7 @@ impl HTMLElement { HTMLElement { element: Element::new_inherited(type_id, tag_name, ns!(HTML), prefix, document), style_decl: Default::default(), + dataset: Default::default(), } } @@ -89,6 +94,11 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { global_event_handlers!(NoOnload) + // https://html.spec.whatwg.org/multipage/dom.html#dom-dataset + fn Dataset(self) -> Temporary<DOMStringMap> { + self.dataset.or_init(|| DOMStringMap::new(self)) + } + fn GetOnload(self) -> Option<EventHandlerNonNull> { if self.is_body_or_frameset() { let win = window_from_node(self).root(); @@ -122,6 +132,51 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { } } +// https://html.spec.whatwg.org/#attr-data-* +pub trait HTMLElementCustomAttributeHelpers { + fn set_custom_attr(self, name: DOMString, value: DOMString) -> ErrorResult; + fn get_custom_attr(self, name: DOMString) -> Option<DOMString>; + fn delete_custom_attr(self, name: DOMString); +} + +fn to_snake_case(name: DOMString) -> DOMString { + let mut attr_name = "data-".into_string(); + for ch in name.as_slice().chars() { + if ch.is_uppercase() { + attr_name.push('\x2d'); + attr_name.push(ch.to_lowercase()); + } else { + attr_name.push(ch); + } + } + attr_name +} + +impl<'a> HTMLElementCustomAttributeHelpers for JSRef<'a, HTMLElement> { + fn set_custom_attr(self, name: DOMString, value: DOMString) -> ErrorResult { + if name.as_slice().chars() + .skip_while(|&ch| ch != '\u002d') + .nth(1).map_or(false, |ch| ch as u8 - b'a' < 26) { + return Err(Syntax); + } + let element: JSRef<Element> = ElementCast::from_ref(self); + element.set_custom_attribute(to_snake_case(name), value) + } + + fn get_custom_attr(self, name: DOMString) -> Option<DOMString> { + let element: JSRef<Element> = ElementCast::from_ref(self); + element.get_attribute(ns!(""), &Atom::from_slice(to_snake_case(name).as_slice())).map(|attr| { + let attr = attr.root(); + attr.value().as_slice().to_string() + }) + } + + fn delete_custom_attr(self, name: DOMString) { + let element: JSRef<Element> = ElementCast::from_ref(self); + element.remove_attribute(ns!(""), to_snake_case(name).as_slice()) + } +} + impl<'a> VirtualMethods for JSRef<'a, HTMLElement> { fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> { let element: &JSRef<Element> = ElementCast::from_borrowed_ref(self); diff --git a/components/script/dom/webidls/DOMStringMap.webidl b/components/script/dom/webidls/DOMStringMap.webidl index aa4d3ed9673..c11d47c5a85 100644 --- a/components/script/dom/webidls/DOMStringMap.webidl +++ b/components/script/dom/webidls/DOMStringMap.webidl @@ -7,6 +7,7 @@ [OverrideBuiltins] interface DOMStringMap { getter DOMString (DOMString name); + [Throws] setter creator void (DOMString name, DOMString value); deleter void (DOMString name); }; diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index 39c7699900d..90ef09d7a9f 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -10,7 +10,7 @@ interface HTMLElement : Element { attribute DOMString lang; // attribute boolean translate; // attribute DOMString dir; - //readonly attribute DOMStringMap dataset; + readonly attribute DOMStringMap dataset; // microdata // attribute boolean itemScope; |