mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Add Event and EventTarget hierarchy via gross AbstractFoo mechanism.
This commit is contained in:
parent
7ecf5abbbd
commit
bb97fd13f3
9 changed files with 327 additions and 86 deletions
|
@ -182,6 +182,9 @@ DOMInterfaces = {
|
||||||
},
|
},
|
||||||
|
|
||||||
'Event': {
|
'Event': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'Event',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'EventListener': {
|
'EventListener': {
|
||||||
|
@ -189,6 +192,10 @@ DOMInterfaces = {
|
||||||
},
|
},
|
||||||
|
|
||||||
'EventTarget': {
|
'EventTarget': {
|
||||||
|
'nativeType': 'AbstractEventTarget',
|
||||||
|
'concreteType': 'EventTarget',
|
||||||
|
'pointerType': '',
|
||||||
|
'needsAbstract': ['dispatchEvent']
|
||||||
},
|
},
|
||||||
|
|
||||||
'FileList': [
|
'FileList': [
|
||||||
|
@ -277,6 +284,9 @@ DOMInterfaces = {
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'MouseEvent': {
|
'MouseEvent': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'MouseEvent',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'Navigator': {
|
'Navigator': {
|
||||||
|
@ -374,6 +384,9 @@ DOMInterfaces = {
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'UIEvent': {
|
'UIEvent': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'UIEvent',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'ValidityState': {
|
'ValidityState': {
|
||||||
|
|
|
@ -2410,12 +2410,13 @@ class Argument():
|
||||||
"""
|
"""
|
||||||
A class for outputting the type and name of an argument
|
A class for outputting the type and name of an argument
|
||||||
"""
|
"""
|
||||||
def __init__(self, argType, name, default=None):
|
def __init__(self, argType, name, default=None, mutable=False):
|
||||||
self.argType = argType
|
self.argType = argType
|
||||||
self.name = name
|
self.name = name
|
||||||
self.default = default
|
self.default = default
|
||||||
|
self.mutable = mutable
|
||||||
def declare(self):
|
def declare(self):
|
||||||
string = self.name + ((': ' + self.argType) if self.argType else '')
|
string = ('mut ' if self.mutable else '') + self.name + ((': ' + self.argType) if self.argType else '')
|
||||||
#XXXjdm Support default arguments somehow :/
|
#XXXjdm Support default arguments somehow :/
|
||||||
#if self.default is not None:
|
#if self.default is not None:
|
||||||
# string += " = " + self.default
|
# string += " = " + self.default
|
||||||
|
@ -5225,6 +5226,8 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::bindings::proxyhandler::*',
|
'dom::bindings::proxyhandler::*',
|
||||||
'dom::document::AbstractDocument',
|
'dom::document::AbstractDocument',
|
||||||
'dom::node::{AbstractNode, ScriptView}',
|
'dom::node::{AbstractNode, ScriptView}',
|
||||||
|
'dom::eventtarget::AbstractEventTarget',
|
||||||
|
'dom::event::AbstractEvent',
|
||||||
'servo_util::vec::zip_copies',
|
'servo_util::vec::zip_copies',
|
||||||
'std::cast',
|
'std::cast',
|
||||||
'std::libc',
|
'std::libc',
|
||||||
|
@ -5652,6 +5655,11 @@ class CGCallback(CGClass):
|
||||||
# CallSetup should re-throw exceptions on aRv.
|
# CallSetup should re-throw exceptions on aRv.
|
||||||
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
||||||
"eReportExceptions"))
|
"eReportExceptions"))
|
||||||
|
|
||||||
|
# Ensure the first argument is mutable
|
||||||
|
args[0] = Argument(args[0].argType, args[0].name, args[0].default, mutable=True)
|
||||||
|
method.args[2] = args[0]
|
||||||
|
|
||||||
# And now insert our template argument.
|
# And now insert our template argument.
|
||||||
argsWithoutThis = list(args)
|
argsWithoutThis = list(args)
|
||||||
args.insert(0, Argument("@mut T", "thisObj"))
|
args.insert(0, Argument("@mut T", "thisObj"))
|
||||||
|
@ -5661,7 +5669,7 @@ class CGCallback(CGClass):
|
||||||
args.insert(0, Argument(None, "&self"))
|
args.insert(0, Argument(None, "&self"))
|
||||||
argsWithoutThis.insert(0, Argument(None, "&self"))
|
argsWithoutThis.insert(0, Argument(None, "&self"))
|
||||||
|
|
||||||
setupCall = ("let s = CallSetup::new(cx_for_dom_object(${cxProvider}), aExceptionHandling);\n"
|
setupCall = ("let s = CallSetup::new(cx_for_dom_object(&mut ${cxProvider}), aExceptionHandling);\n"
|
||||||
"if s.GetContext().is_null() {\n"
|
"if s.GetContext().is_null() {\n"
|
||||||
" return${errorReturn};\n"
|
" return${errorReturn};\n"
|
||||||
"}\n")
|
"}\n")
|
||||||
|
@ -5676,7 +5684,7 @@ class CGCallback(CGClass):
|
||||||
"errorReturn" : method.getDefaultRetval(),
|
"errorReturn" : method.getDefaultRetval(),
|
||||||
"callArgs" : ", ".join(argnamesWithThis),
|
"callArgs" : ", ".join(argnamesWithThis),
|
||||||
"methodName": 'self.' + method.name,
|
"methodName": 'self.' + method.name,
|
||||||
"cxProvider": 'thisObj'
|
"cxProvider": '*thisObj'
|
||||||
})
|
})
|
||||||
bodyWithoutThis = string.Template(
|
bodyWithoutThis = string.Template(
|
||||||
setupCall +
|
setupCall +
|
||||||
|
|
|
@ -768,6 +768,7 @@ pub enum Error {
|
||||||
NotFound,
|
NotFound,
|
||||||
HierarchyRequest,
|
HierarchyRequest,
|
||||||
InvalidCharacter,
|
InvalidCharacter,
|
||||||
|
NotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Fallible<T> = Result<T, Error>;
|
pub type Fallible<T> = Result<T, Error>;
|
||||||
|
@ -841,7 +842,7 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
#[fixed_stack_segment]
|
||||||
fn cx_for_dom_wrapper(obj: *JSObject) -> *JSContext {
|
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
|
||||||
unsafe {
|
unsafe {
|
||||||
let global = GetGlobalForObjectCrossCompartment(obj);
|
let global = GetGlobalForObjectCrossCompartment(obj);
|
||||||
let clasp = JS_GetClass(global);
|
let clasp = JS_GetClass(global);
|
||||||
|
@ -860,8 +861,8 @@ fn cx_for_dom_wrapper(obj: *JSObject) -> *JSContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cx_for_dom_object<T: Reflectable>(obj: @mut T) -> *JSContext {
|
pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
|
||||||
cx_for_dom_wrapper(obj.reflector().get_jsobject())
|
cx_for_dom_reflector(obj.reflector().get_jsobject())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
||||||
|
|
|
@ -5,16 +5,20 @@
|
||||||
use dom::comment::Comment;
|
use dom::comment::Comment;
|
||||||
use dom::bindings::codegen::DocumentBinding;
|
use dom::bindings::codegen::DocumentBinding;
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
|
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper};
|
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper, NotSupported};
|
||||||
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, null_str_as_empty, null_str_as_word_null};
|
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable};
|
||||||
|
use dom::bindings::utils::{null_str_as_empty_ref, null_str_as_empty, null_str_as_word_null};
|
||||||
use dom::documentfragment::DocumentFragment;
|
use dom::documentfragment::DocumentFragment;
|
||||||
use dom::element::{Element};
|
use dom::element::{Element};
|
||||||
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
||||||
use dom::event::Event;
|
use dom::event::{AbstractEvent, Event, HTMLEventTypeId, UIEventTypeId};
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmldocument::HTMLDocument;
|
use dom::htmldocument::HTMLDocument;
|
||||||
|
use dom::htmlelement::HTMLElement;
|
||||||
|
use dom::mouseevent::MouseEvent;
|
||||||
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::htmltitleelement::HTMLTitleElement;
|
use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use html::hubbub_html_parser::build_element_from_tag;
|
use html::hubbub_html_parser::build_element_from_tag;
|
||||||
|
@ -256,9 +260,13 @@ impl Document {
|
||||||
Comment::new(null_str_as_word_null(data), abstract_self)
|
Comment::new(null_str_as_word_null(data), abstract_self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<@mut Event> {
|
pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<AbstractEvent> {
|
||||||
//FIXME: We need to do a proper Event inheritance simulation
|
match null_str_as_empty_ref(interface) {
|
||||||
Ok(Event::new(self.window, interface))
|
"UIEvents" => Ok(UIEvent::new(self.window, UIEventTypeId)),
|
||||||
|
"MouseEvents" => Ok(MouseEvent::new(self.window)),
|
||||||
|
"HTMLEvents" => Ok(Event::new(self.window, HTMLEventTypeId)),
|
||||||
|
_ => Err(NotSupported)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Title(&self, _: AbstractDocument) -> DOMString {
|
pub fn Title(&self, _: AbstractDocument) -> DOMString {
|
||||||
|
|
|
@ -2,17 +2,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::AbstractEventTarget;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::bindings::codegen::EventBinding;
|
use dom::bindings::codegen::EventBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object, DerivedWrapper};
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, Fallible, null_str_as_word_null};
|
use dom::bindings::utils::{DOMString, ErrorResult, Fallible, null_str_as_word_null};
|
||||||
|
use dom::mouseevent::MouseEvent;
|
||||||
|
use dom::uievent::UIEvent;
|
||||||
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
|
||||||
use script_task::page_from_context;
|
use script_task::page_from_context;
|
||||||
|
|
||||||
|
use std::cast;
|
||||||
|
use std::unstable::raw::Box;
|
||||||
|
|
||||||
pub enum Event_ {
|
pub enum Event_ {
|
||||||
ResizeEvent(uint, uint),
|
ResizeEvent(uint, uint),
|
||||||
ReflowEvent,
|
ReflowEvent,
|
||||||
|
@ -21,7 +27,116 @@ pub enum Event_ {
|
||||||
MouseUpEvent(uint, Point2D<f32>),
|
MouseUpEvent(uint, Point2D<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AbstractEvent {
|
||||||
|
event: *mut Box<Event>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractEvent {
|
||||||
|
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
|
||||||
|
AbstractEvent {
|
||||||
|
event: box
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Downcasting borrows
|
||||||
|
//
|
||||||
|
|
||||||
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
|
unsafe {
|
||||||
|
let box: *Box<T> = self.event as *Box<T>;
|
||||||
|
&(*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
|
||||||
|
unsafe {
|
||||||
|
let box: *mut Box<T> = self.event as *mut Box<T>;
|
||||||
|
&mut (*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_id(&self) -> EventTypeId {
|
||||||
|
self.event().type_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event<'a>(&'a self) -> &'a Event {
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_event<'a>(&'a self) -> &'a mut Event {
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_uievent(&self) -> bool {
|
||||||
|
self.type_id() == UIEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uievent<'a>(&'a self) -> &'a UIEvent {
|
||||||
|
assert!(self.is_uievent());
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_uievent<'a>(&'a self) -> &'a mut UIEvent {
|
||||||
|
assert!(self.is_uievent());
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_mouseevent(&self) -> bool {
|
||||||
|
self.type_id() == MouseEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouseevent<'a>(&'a self) -> &'a MouseEvent {
|
||||||
|
assert!(self.is_mouseevent());
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_mouseevent<'a>(&'a self) -> &'a mut MouseEvent {
|
||||||
|
assert!(self.is_mouseevent());
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for AbstractEvent {
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
|
let wrapper = self.reflector().get_jsobject();
|
||||||
|
if wrapper.is_not_null() {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reflectable for AbstractEvent {
|
||||||
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
self.event().reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
|
self.mut_event().mut_reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
fail!(~"doesn't make any sense");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
|
||||||
|
self.event().GetParentObject(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Eq)]
|
||||||
|
pub enum EventTypeId {
|
||||||
|
HTMLEventTypeId,
|
||||||
|
UIEventTypeId,
|
||||||
|
MouseEventTypeId,
|
||||||
|
KeyEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
|
type_id: EventTypeId,
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
type_: ~str,
|
type_: ~str,
|
||||||
default_prevented: bool,
|
default_prevented: bool,
|
||||||
|
@ -31,10 +146,11 @@ pub struct Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
pub fn new_inherited(type_: &DOMString) -> Event {
|
pub fn new_inherited(type_id: EventTypeId) -> Event {
|
||||||
Event {
|
Event {
|
||||||
|
type_id: type_id,
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
type_: null_str_as_word_null(type_),
|
type_: ~"",
|
||||||
default_prevented: false,
|
default_prevented: false,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
|
@ -42,8 +158,18 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: @mut Window, type_: &DOMString) -> @mut Event {
|
//FIXME: E should be bounded by some trait that is only implemented for Event types
|
||||||
reflect_dom_object(@mut Event::new_inherited(type_), window, EventBinding::Wrap)
|
pub fn as_abstract<E>(event: @mut E) -> AbstractEvent {
|
||||||
|
// This surrenders memory management of the event!
|
||||||
|
AbstractEvent {
|
||||||
|
event: unsafe { cast::transmute(event) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(window: @mut Window, type_id: EventTypeId) -> AbstractEvent {
|
||||||
|
let ev = reflect_dom_object(@mut Event::new_inherited(type_id), window,
|
||||||
|
EventBinding::Wrap);
|
||||||
|
Event::as_abstract(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn EventPhase(&self) -> u16 {
|
pub fn EventPhase(&self) -> u16 {
|
||||||
|
@ -54,11 +180,11 @@ impl Event {
|
||||||
Some(self.type_.clone())
|
Some(self.type_.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetCurrentTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetCurrentTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +218,7 @@ impl Event {
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
bubbles: bool,
|
bubbles: bool,
|
||||||
cancelable: bool) -> ErrorResult {
|
cancelable: bool) -> ErrorResult {
|
||||||
self.type_ = type_.to_str();
|
self.type_ = null_str_as_word_null(type_);
|
||||||
self.cancelable = cancelable;
|
self.cancelable = cancelable;
|
||||||
self.bubbles = bubbles;
|
self.bubbles = bubbles;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -104,8 +230,10 @@ impl Event {
|
||||||
|
|
||||||
pub fn Constructor(global: @mut Window,
|
pub fn Constructor(global: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
_init: &EventBinding::EventInit) -> Fallible<@mut Event> {
|
init: &EventBinding::EventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(Event::new(global, type_))
|
let ev = Event::new(global, HTMLEventTypeId);
|
||||||
|
ev.mut_event().InitEvent(type_, init.bubbles, init.cancelable);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,19 @@
|
||||||
|
|
||||||
use dom::bindings::callback::eReportExceptions;
|
use dom::bindings::callback::eReportExceptions;
|
||||||
use dom::bindings::codegen::EventTargetBinding;
|
use dom::bindings::codegen::EventTargetBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, DOMString, Fallible};
|
use dom::bindings::utils::{Reflectable, Reflector, DOMString, Fallible, DerivedWrapper};
|
||||||
|
use dom::bindings::utils::null_str_as_word_null;
|
||||||
use dom::bindings::codegen::EventListenerBinding::EventListener;
|
use dom::bindings::codegen::EventListenerBinding::EventListener;
|
||||||
use dom::event::Event;
|
use dom::event::AbstractEvent;
|
||||||
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use script_task::page_from_context;
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
|
||||||
|
use std::cast;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
|
use std::unstable::raw::Box;
|
||||||
|
|
||||||
pub struct EventTarget {
|
pub struct EventTarget {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
@ -19,6 +24,80 @@ pub struct EventTarget {
|
||||||
bubbling_handlers: HashMap<~str, ~[EventListener]>
|
bubbling_handlers: HashMap<~str, ~[EventListener]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AbstractEventTarget {
|
||||||
|
eventtarget: *mut Box<EventTarget>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractEventTarget {
|
||||||
|
pub fn from_box(box: *mut Box<EventTarget>) -> AbstractEventTarget {
|
||||||
|
AbstractEventTarget {
|
||||||
|
eventtarget: box
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_node(node: AbstractNode<ScriptView>) -> AbstractEventTarget {
|
||||||
|
unsafe {
|
||||||
|
cast::transmute(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Downcasting borrows
|
||||||
|
//
|
||||||
|
|
||||||
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
|
unsafe {
|
||||||
|
let box: *Box<T> = self.eventtarget as *Box<T>;
|
||||||
|
&(*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
|
||||||
|
unsafe {
|
||||||
|
let box: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
||||||
|
&mut (*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eventtarget<'a>(&'a self) -> &'a EventTarget {
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_eventtarget<'a>(&'a mut self) -> &'a mut EventTarget {
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for AbstractEventTarget {
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
|
let wrapper = self.reflector().get_jsobject();
|
||||||
|
if wrapper.is_not_null() {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reflectable for AbstractEventTarget {
|
||||||
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
self.eventtarget().reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
|
self.mut_eventtarget().mut_reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
|
||||||
|
self.eventtarget().GetParentObject(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EventTarget {
|
impl EventTarget {
|
||||||
pub fn new() -> EventTarget {
|
pub fn new() -> EventTarget {
|
||||||
EventTarget {
|
EventTarget {
|
||||||
|
@ -46,7 +125,7 @@ impl EventTarget {
|
||||||
} else {
|
} else {
|
||||||
&mut self.bubbling_handlers
|
&mut self.bubbling_handlers
|
||||||
};
|
};
|
||||||
let entry = handlers.find_or_insert_with(ty.to_str(), |_| ~[]);
|
let entry = handlers.find_or_insert_with(null_str_as_word_null(ty), |_| ~[]);
|
||||||
if entry.position_elem(listener).is_none() {
|
if entry.position_elem(listener).is_none() {
|
||||||
entry.push((*listener).clone());
|
entry.push((*listener).clone());
|
||||||
}
|
}
|
||||||
|
@ -63,7 +142,7 @@ impl EventTarget {
|
||||||
} else {
|
} else {
|
||||||
&mut self.bubbling_handlers
|
&mut self.bubbling_handlers
|
||||||
};
|
};
|
||||||
let mut entry = handlers.find_mut(&ty.to_str());
|
let mut entry = handlers.find_mut(&null_str_as_word_null(ty));
|
||||||
for entry in entry.mut_iter() {
|
for entry in entry.mut_iter() {
|
||||||
let position = entry.position_elem(listener);
|
let position = entry.position_elem(listener);
|
||||||
for &position in position.iter() {
|
for &position in position.iter() {
|
||||||
|
@ -73,24 +152,25 @@ impl EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn DispatchEvent(&self, event: @mut Event) -> Fallible<bool> {
|
pub fn DispatchEvent(&self, _abstract_self: AbstractEventTarget, event: AbstractEvent) -> Fallible<bool> {
|
||||||
//FIXME: get proper |this| object
|
//FIXME: get proper |this| object
|
||||||
|
|
||||||
let maybe_handlers = self.capturing_handlers.find(&event.type_);
|
let type_ = event.event().type_.clone();
|
||||||
|
let maybe_handlers = self.capturing_handlers.find(&type_);
|
||||||
for handlers in maybe_handlers.iter() {
|
for handlers in maybe_handlers.iter() {
|
||||||
for handler in handlers.iter() {
|
for handler in handlers.iter() {
|
||||||
handler.HandleEvent__(event, eReportExceptions);
|
handler.HandleEvent__(event, eReportExceptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if event.bubbles {
|
if event.event().bubbles {
|
||||||
let maybe_handlers = self.bubbling_handlers.find(&event.type_);
|
let maybe_handlers = self.bubbling_handlers.find(&type_);
|
||||||
for handlers in maybe_handlers.iter() {
|
for handlers in maybe_handlers.iter() {
|
||||||
for handler in handlers.iter() {
|
for handler in handlers.iter() {
|
||||||
handler.HandleEvent__(event, eReportExceptions);
|
handler.HandleEvent__(event, eReportExceptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(!event.DefaultPrevented())
|
Ok(!event.event().DefaultPrevented())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
use dom::bindings::codegen::MouseEventBinding;
|
use dom::bindings::codegen::MouseEventBinding;
|
||||||
use dom::bindings::utils::{ErrorResult, Fallible, DOMString};
|
use dom::bindings::utils::{ErrorResult, Fallible, DOMString};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::event::{AbstractEvent, Event, MouseEventTypeId};
|
||||||
|
use dom::eventtarget::AbstractEventTarget;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
|
@ -23,38 +24,42 @@ pub struct MouseEvent {
|
||||||
alt_key: bool,
|
alt_key: bool,
|
||||||
meta_key: bool,
|
meta_key: bool,
|
||||||
button: u16,
|
button: u16,
|
||||||
related_target: Option<@mut EventTarget>
|
related_target: Option<AbstractEventTarget>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseEvent {
|
impl MouseEvent {
|
||||||
pub fn new(window: @mut Window, type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new_inherited() -> MouseEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32, screen_x: i32,
|
MouseEvent {
|
||||||
screen_y: i32, client_x: i32, client_y: i32, ctrl_key: bool,
|
parent: UIEvent::new_inherited(MouseEventTypeId),
|
||||||
shift_key: bool, alt_key: bool, meta_key: bool, button: u16,
|
screen_x: 0,
|
||||||
_buttons: u16, related_target: Option<@mut EventTarget>) -> @mut MouseEvent {
|
screen_y: 0,
|
||||||
let ev = @mut MouseEvent {
|
client_x: 0,
|
||||||
parent: UIEvent::new_inherited(type_, can_bubble, cancelable, view, detail),
|
client_y: 0,
|
||||||
screen_x: screen_x,
|
ctrl_key: false,
|
||||||
screen_y: screen_y,
|
shift_key: false,
|
||||||
client_x: client_x,
|
alt_key: false,
|
||||||
client_y: client_y,
|
meta_key: false,
|
||||||
ctrl_key: ctrl_key,
|
button: 0,
|
||||||
shift_key: shift_key,
|
related_target: None
|
||||||
alt_key: alt_key,
|
}
|
||||||
meta_key: meta_key,
|
}
|
||||||
button: button,
|
|
||||||
related_target: related_target
|
pub fn new(window: @mut Window) -> AbstractEvent {
|
||||||
};
|
Event::as_abstract(reflect_dom_object(@mut MouseEvent::new_inherited(),
|
||||||
reflect_dom_object(ev, window, MouseEventBinding::Wrap)
|
window,
|
||||||
|
MouseEventBinding::Wrap))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(owner: @mut Window,
|
pub fn Constructor(owner: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
init: &MouseEventBinding::MouseEventInit) -> Fallible<@mut MouseEvent> {
|
init: &MouseEventBinding::MouseEventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(MouseEvent::new(owner, type_, init.bubbles, init.cancelable, init.view, init.detail,
|
let ev = MouseEvent::new(owner);
|
||||||
init.screenX, init.screenY, init.clientX, init.clientY,
|
ev.mut_mouseevent().InitMouseEvent(type_, init.bubbles, init.cancelable, init.view,
|
||||||
init.ctrlKey, init.shiftKey, init.altKey, init.metaKey,
|
init.detail, init.screenX, init.screenY,
|
||||||
init.button, init.buttons, init.relatedTarget))
|
init.clientX, init.clientY, init.ctrlKey,
|
||||||
|
init.altKey, init.shiftKey, init.metaKey,
|
||||||
|
init.button, init.relatedTarget);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ScreenX(&self) -> i32 {
|
pub fn ScreenX(&self) -> i32 {
|
||||||
|
@ -98,7 +103,7 @@ impl MouseEvent {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetRelatedTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetRelatedTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
self.related_target
|
self.related_target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +127,7 @@ impl MouseEvent {
|
||||||
shiftKeyArg: bool,
|
shiftKeyArg: bool,
|
||||||
metaKeyArg: bool,
|
metaKeyArg: bool,
|
||||||
buttonArg: u16,
|
buttonArg: u16,
|
||||||
relatedTargetArg: Option<@mut EventTarget>) -> ErrorResult {
|
relatedTargetArg: Option<AbstractEventTarget>) -> ErrorResult {
|
||||||
self.parent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
|
self.parent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
|
||||||
self.screen_x = screenXArg;
|
self.screen_x = screenXArg;
|
||||||
self.screen_y = screenYArg;
|
self.screen_y = screenYArg;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::codegen::UIEventBinding;
|
||||||
use dom::bindings::utils::{DOMString, Fallible};
|
use dom::bindings::utils::{DOMString, Fallible};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use dom::event::Event;
|
use dom::event::{AbstractEvent, Event, EventTypeId, UIEventTypeId};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
|
|
||||||
|
@ -14,36 +14,33 @@ use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
pub struct UIEvent {
|
pub struct UIEvent {
|
||||||
parent: Event,
|
parent: Event,
|
||||||
can_bubble: bool,
|
|
||||||
cancelable: bool,
|
|
||||||
view: Option<@mut WindowProxy>,
|
view: Option<@mut WindowProxy>,
|
||||||
detail: i32
|
detail: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIEvent {
|
impl UIEvent {
|
||||||
pub fn new_inherited(type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32) -> UIEvent {
|
|
||||||
UIEvent {
|
UIEvent {
|
||||||
parent: Event::new_inherited(type_),
|
parent: Event::new_inherited(type_id),
|
||||||
can_bubble: can_bubble,
|
view: None,
|
||||||
cancelable: cancelable,
|
detail: 0
|
||||||
view: view,
|
|
||||||
detail: detail
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: @mut Window, type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new(window: @mut Window, type_id: EventTypeId) -> AbstractEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32) -> @mut UIEvent {
|
let ev = reflect_dom_object(@mut UIEvent::new_inherited(type_id),
|
||||||
reflect_dom_object(@mut UIEvent::new_inherited(type_, can_bubble, cancelable, view, detail),
|
|
||||||
window,
|
window,
|
||||||
UIEventBinding::Wrap)
|
UIEventBinding::Wrap);
|
||||||
|
Event::as_abstract(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(owner: @mut Window,
|
pub fn Constructor(owner: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
init: &UIEventBinding::UIEventInit) -> Fallible<@mut UIEvent> {
|
init: &UIEventBinding::UIEventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(UIEvent::new(owner, type_, init.parent.bubbles, init.parent.cancelable,
|
let ev = UIEvent::new(owner, UIEventTypeId);
|
||||||
init.view, init.detail))
|
ev.mut_uievent().InitUIEvent(type_, init.parent.bubbles, init.parent.cancelable,
|
||||||
|
init.view, init.detail);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetView(&self) -> Option<@mut WindowProxy> {
|
pub fn GetView(&self) -> Option<@mut WindowProxy> {
|
||||||
|
@ -61,8 +58,6 @@ impl UIEvent {
|
||||||
view: Option<@mut WindowProxy>,
|
view: Option<@mut WindowProxy>,
|
||||||
detail: i32) {
|
detail: i32) {
|
||||||
self.parent.InitEvent(type_, can_bubble, cancelable);
|
self.parent.InitEvent(type_, can_bubble, cancelable);
|
||||||
self.can_bubble = can_bubble;
|
|
||||||
self.cancelable = cancelable;
|
|
||||||
self.view = view;
|
self.view = view;
|
||||||
self.detail = detail;
|
self.detail = detail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,17 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
|
var saw_event = false;
|
||||||
function onFoopy() {
|
function onFoopy() {
|
||||||
window.removeEventListener('foopy', onFoopy);
|
window.removeEventListener('foopy', onFoopy);
|
||||||
finish();
|
saw_event = true;
|
||||||
}
|
}
|
||||||
window.addEventListener('foopy', onFoopy);
|
window.addEventListener('foopy', onFoopy);
|
||||||
var ev = document.createEvent('Event');
|
var ev = document.createEvent('HTMLEvents');
|
||||||
ev.initEvent('foopy', true, true);
|
ev.initEvent('foopy', true, true);
|
||||||
window.dispatchEvent(ev);
|
window.dispatchEvent(ev);
|
||||||
|
is(saw_event, true);
|
||||||
|
finish();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue