Files
tubestation/servo/components/script/dom/htmlelement.rs
Josh Matthews b9717a975e servo: Merge #4342 - Implement basic HTMLElement.style support (from jdm:cssom); r=jdm,metajack
This does not implement any notion of CSSStyleDeclaration objects that do not have an owning element; there's no actual CSS object model in play here. This does support setting and getting properties of the style attribute for HTMLElement, and tries to implement the ambiguous CSS value serialization spec.

Source-Repo: https://github.com/servo/servo
Source-Revision: 824788649cd338c044d9396166af5b0f378d6685
2014-12-18 11:54:52 -07:00

152 lines
5.4 KiB
Rust

/* 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;
use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLElementBinding;
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
use dom::bindings::js::{JSRef, Temporary, MutNullableJS};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::cssstyledeclaration::CSSStyleDeclaration;
use dom::document::Document;
use dom::element::{Element, ElementTypeId, ActivationElementHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::node::{Node, NodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use servo_util::str::DOMString;
use string_cache::Atom;
use std::default::Default;
#[dom_struct]
pub struct HTMLElement {
element: Element,
style_decl: MutNullableJS<CSSStyleDeclaration>,
}
impl HTMLElementDerived for EventTarget {
fn is_htmlelement(&self) -> bool {
match *self.type_id() {
EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::Element)) => false,
EventTargetTypeId::Node(NodeTypeId::Element(_)) => true,
_ => false
}
}
}
impl HTMLElement {
pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLElement {
HTMLElement {
element: Element::new_inherited(type_id, tag_name, ns!(HTML), prefix, document),
style_decl: Default::default(),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLElement> {
let element = HTMLElement::new_inherited(ElementTypeId::HTMLElement, localName, prefix, document);
Node::reflect_node(box element, document, HTMLElementBinding::Wrap)
}
}
trait PrivateHTMLElementHelpers {
fn is_body_or_frameset(self) -> bool;
}
impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> {
fn is_body_or_frameset(self) -> bool {
let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.is_htmlbodyelement() || eventtarget.is_htmlframesetelement()
}
}
impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
fn Style(self) -> Temporary<CSSStyleDeclaration> {
self.style_decl.or_init(|| {
let global = window_from_node(self).root();
CSSStyleDeclaration::new(*global, self)
})
}
make_getter!(Title)
make_setter!(SetTitle, "title")
make_getter!(Lang)
make_setter!(SetLang, "lang")
// http://html.spec.whatwg.org/multipage/#dom-hidden
make_bool_getter!(Hidden)
make_bool_setter!(SetHidden, "hidden")
global_event_handlers!(NoOnload)
fn GetOnload(self) -> Option<EventHandlerNonNull> {
if self.is_body_or_frameset() {
let win = window_from_node(self).root();
win.GetOnload()
} else {
None
}
}
fn SetOnload(self, listener: Option<EventHandlerNonNull>) {
if self.is_body_or_frameset() {
let win = window_from_node(self).root();
win.SetOnload(listener)
}
}
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click
fn Click(self) {
let maybe_input = HTMLInputElementCast::to_ref(self);
match maybe_input {
Some(i) if i.Disabled() => return,
_ => ()
}
let element: JSRef<Element> = ElementCast::from_ref(self);
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27430 ?
element.as_maybe_activatable().map(|a| a.synthetic_click_activation(false, false, false, false));
}
}
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);
Some(element as &VirtualMethods)
}
fn after_set_attr(&self, attr: JSRef<Attr>) {
match self.super_type() {
Some(ref s) => s.after_set_attr(attr),
_ => ()
}
let name = attr.local_name().as_slice();
if name.starts_with("on") {
let window = window_from_node(*self).root();
let (cx, url, reflector) = (window.get_cx(),
window.get_url(),
window.reflector().get_jsobject());
let evtarget: JSRef<EventTarget> = EventTargetCast::from_ref(*self);
evtarget.set_event_handler_uncompiled(cx, url, reflector,
name.slice_from(2),
attr.value().as_slice().to_string());
}
}
}
impl Reflectable for HTMLElement {
fn reflector<'a>(&'a self) -> &'a Reflector {
self.element.reflector()
}
}