Add stubs for inline event handler manipulation.

This commit is contained in:
Josh Matthews 2014-04-21 20:19:32 -04:00 committed by Ms2ger
parent 2717ab65ec
commit 2d6153772c
10 changed files with 223 additions and 23 deletions

View file

@ -34,6 +34,7 @@ DOMInterfaces = {
'DOMParser': {}, 'DOMParser': {},
'Element': {}, 'Element': {},
'Event': {}, 'Event': {},
'EventHandler': {},
'EventListener': { 'EventListener': {
'nativeType': 'EventListenerBinding::EventListener', 'nativeType': 'EventListenerBinding::EventListener',
}, },

View file

@ -705,17 +705,17 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
"rooting issues") "rooting issues")
# XXXbz we're going to assume that callback types are always # XXXbz we're going to assume that callback types are always
# nullable and always have [TreatNonCallableAsNull] for now. # nullable and always have [TreatNonCallableAsNull] for now.
haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())" haveCallable = "${val}.is_object() && JS_ObjectIsCallable(cx, ${val}.to_object()) != 0"
if defaultValue is not None: if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue)) assert(isinstance(defaultValue, IDLNullValue))
haveCallable = "${haveValue} && " + haveCallable haveCallable = "${haveValue} && " + haveCallable
return ( return (
"if (%s) {\n" "if (%s) {\n"
" ${declName} = &${val}.toObject();\n" " ${val}.to_object()\n"
"} else {\n" "} else {\n"
" ${declName} = NULL;\n" " ptr::mut_null()\n"
"}" % haveCallable, "}" % haveCallable,
CGGeneric("JSObject*"), None, needsRooting) CGGeneric("*mut JSObject"), needsRooting)
if type.isAny(): if type.isAny():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
@ -1346,6 +1346,14 @@ class CGIfWrapper(CGWrapper):
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(), CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
post="\n}") post="\n}")
class CGTemplatedType(CGWrapper):
def __init__(self, templateName, child, isConst=False, isReference=False):
const = "const " if isConst else ""
pre = "%s%s<" % (const, templateName)
ref = "&" if isReference else ""
post = ">%s" % ref
CGWrapper.__init__(self, child, pre=pre, post=post)
class CGNamespace(CGWrapper): class CGNamespace(CGWrapper):
def __init__(self, namespace, child, public=False): def __init__(self, namespace, child, public=False):
pre = "%smod %s {\n" % ("pub " if public else "", namespace) pre = "%smod %s {\n" % ("pub " if public else "", namespace)
@ -3128,7 +3136,7 @@ class ClassMember(ClassItem):
ClassItem.__init__(self, name, visibility) ClassItem.__init__(self, name, visibility)
def declare(self, cgClass): def declare(self, cgClass):
return '%s: %s,\n' % (self.name, self.type) return '%s %s: %s,\n' % (self.visibility, self.name, self.type)
def define(self, cgClass): def define(self, cgClass):
if not self.static: if not self.static:
@ -4357,7 +4365,7 @@ class CGNativeMember(ClassMethod):
elif type.isAny(): elif type.isAny():
typeDecl, template = "JS::Value", "return ${declName};" typeDecl, template = "JS::Value", "return ${declName};"
elif type.isObject(): elif type.isObject():
typeDecl, template = "JSObject*", "return ${declName};" typeDecl, template = "*JSObject", "return ${declName};"
elif type.isSpiderMonkeyInterface(): elif type.isSpiderMonkeyInterface():
if type.nullable(): if type.nullable():
returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();" returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
@ -4561,7 +4569,7 @@ class CGNativeMember(ClassMethod):
elif optional: elif optional:
# Note: All variadic args claim to be optional, but we can just use # Note: All variadic args claim to be optional, but we can just use
# empty arrays to represent them not being present. # empty arrays to represent them not being present.
decl = CGTemplatedType("Optional", decl) decl = CGTemplatedType("Option", decl)
ref = True ref = True
return (decl, ref) return (decl, ref)
@ -4816,6 +4824,7 @@ class CallbackMember(CGNativeMember):
def getResultConversion(self): def getResultConversion(self):
replacements = { replacements = {
"val": "rval", "val": "rval",
"declName": "rvalDecl",
} }
if isJSImplementedDescriptor(self.descriptorProvider): if isJSImplementedDescriptor(self.descriptorProvider):

View file

@ -9,7 +9,7 @@ use dom::bindings::utils::jsstring_to_str;
use dom::bindings::utils::unwrap_jsmanaged; use dom::bindings::utils::unwrap_jsmanaged;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use js::jsapi::{JSBool, JSContext}; use js::jsapi::{JSBool, JSContext, JSObject};
use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64}; use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64};
use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32}; use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32};
use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean};
@ -18,7 +18,7 @@ use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
use js::jsapi::{JS_WrapValue}; use js::jsapi::{JS_WrapValue};
use js::jsval::JSVal; use js::jsval::JSVal;
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value}; use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
use js::jsval::{StringValue, ObjectValue}; use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
use js::glue::RUST_JS_NumberValue; use js::glue::RUST_JS_NumberValue;
use libc; use libc;
use std::default::Default; use std::default::Default;
@ -348,3 +348,9 @@ impl<X: Default, T: FromJSValConvertible<X>> FromJSValConvertible<()> for Option
} }
} }
} }
impl ToJSValConvertible for *mut JSObject {
fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
ObjectOrNullValue(*self)
}
}

View file

@ -5,6 +5,7 @@
use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::BindingDeclarations::DocumentBinding; use dom::bindings::codegen::BindingDeclarations::DocumentBinding;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable}; use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable};
use dom::bindings::js::OptionalRootable; use dom::bindings::js::OptionalRootable;
@ -21,7 +22,7 @@ use dom::element::{Element, AttributeHandlers, get_attribute_parts};
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId}; use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId}; use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId};
use dom::event::Event; use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
use dom::htmlcollection::{HTMLCollection, CollectionFilter}; use dom::htmlcollection::{HTMLCollection, CollectionFilter};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::htmlheadelement::HTMLHeadElement; use dom::htmlheadelement::HTMLHeadElement;
@ -44,7 +45,7 @@ use servo_util::namespace::{Namespace, Null};
use servo_util::str::{DOMString, null_str_as_empty_ref}; use servo_util::str::{DOMString, null_str_as_empty_ref};
use collections::hashmap::HashMap; use collections::hashmap::HashMap;
use js::jsapi::JSContext; use js::jsapi::{JSObject, JSContext};
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
use url::{Url, from_str}; use url::{Url, from_str};
@ -325,6 +326,8 @@ pub trait DocumentMethods {
fn Applets(&self) -> Temporary<HTMLCollection>; fn Applets(&self) -> Temporary<HTMLCollection>;
fn Location(&mut self) -> Temporary<Location>; fn Location(&mut self) -> Temporary<Location>;
fn Children(&self) -> Temporary<HTMLCollection>; fn Children(&self) -> Temporary<HTMLCollection>;
fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject;
fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
} }
impl<'a> DocumentMethods for JSRef<'a, Document> { impl<'a> DocumentMethods for JSRef<'a, Document> {
@ -804,4 +807,14 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
let window = self.window.root(); let window = self.window.root();
HTMLCollection::children(&*window, NodeCast::from_ref(self)) HTMLCollection::children(&*window, NodeCast::from_ref(self))
} }
fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("load")
}
fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("load", listener)
}
} }

View file

@ -2,16 +2,19 @@
* 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::bindings::callback::CallbackContainer;
use dom::bindings::codegen::BindingDeclarations::EventListenerBinding::EventListener;
use dom::bindings::error::{Fallible, InvalidState};
use dom::bindings::js::JSRef; use dom::bindings::js::JSRef;
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::error::{Fallible, InvalidState};
use dom::bindings::codegen::BindingDeclarations::EventListenerBinding::EventListener;
use dom::event::Event; use dom::event::Event;
use dom::eventdispatcher::dispatch_event; use dom::eventdispatcher::dispatch_event;
use dom::node::NodeTypeId; use dom::node::NodeTypeId;
use dom::xmlhttprequest::XMLHttpRequestId; use dom::xmlhttprequest::XMLHttpRequestId;
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use js::jsapi::JSObject;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use std::ptr;
use collections::hashmap::HashMap; use collections::hashmap::HashMap;
@ -28,10 +31,24 @@ pub enum EventTargetTypeId {
XMLHttpRequestTargetTypeId(XMLHttpRequestId) XMLHttpRequestTargetTypeId(XMLHttpRequestId)
} }
#[deriving(Eq, Encodable)]
pub enum EventListenerType {
Additive(EventListener),
Inline(EventListener),
}
impl EventListenerType {
fn get_listener(&self) -> EventListener {
match *self {
Additive(listener) | Inline(listener) => listener
}
}
}
#[deriving(Eq,Encodable)] #[deriving(Eq,Encodable)]
pub struct EventListenerEntry { pub struct EventListenerEntry {
pub phase: ListenerPhase, pub phase: ListenerPhase,
pub listener: EventListener pub listener: EventListenerType
} }
#[deriving(Encodable)] #[deriving(Encodable)]
@ -52,7 +69,7 @@ impl EventTarget {
pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListener>> { pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListener>> {
self.handlers.find_equiv(&type_).map(|listeners| { self.handlers.find_equiv(&type_).map(|listeners| {
listeners.iter().map(|entry| entry.listener).collect() listeners.iter().map(|entry| entry.listener.get_listener()).collect()
}) })
} }
@ -60,7 +77,7 @@ impl EventTarget {
-> Option<Vec<EventListener>> { -> Option<Vec<EventListener>> {
self.handlers.find_equiv(&type_).map(|listeners| { self.handlers.find_equiv(&type_).map(|listeners| {
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase); let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
filtered.map(|entry| entry.listener).collect() filtered.map(|entry| entry.listener.get_listener()).collect()
}) })
} }
} }
@ -69,6 +86,12 @@ pub trait EventTargetHelpers {
fn dispatch_event_with_target<'a>(&self, fn dispatch_event_with_target<'a>(&self,
target: Option<JSRef<'a, EventTarget>>, target: Option<JSRef<'a, EventTarget>>,
event: &mut JSRef<Event>) -> Fallible<bool>; event: &mut JSRef<Event>) -> Fallible<bool>;
fn set_inline_event_listener(&mut self,
ty: DOMString,
listener: Option<EventListener>);
fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener>;
fn set_event_handler_common(&mut self, ty: &str, listener: *mut JSObject);
fn get_event_handler_common(&self, ty: &str) -> *mut JSObject;
} }
impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> { impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
@ -80,6 +103,57 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
} }
Ok(dispatch_event(self, target, event)) Ok(dispatch_event(self, target, event))
} }
fn set_inline_event_listener(&mut self,
ty: DOMString,
listener: Option<EventListener>) {
let entries = self.handlers.find_or_insert_with(ty, |_| vec!());
let idx = entries.iter().position(|&entry| {
match entry.listener {
Inline(_) => true,
_ => false,
}
});
match idx {
Some(idx) => {
match listener {
Some(listener) => entries.get_mut(idx).listener = Inline(listener),
None => {
entries.remove(idx);
}
}
}
None => {
if listener.is_some() {
entries.push(EventListenerEntry {
phase: Capturing, //XXXjdm no idea when inline handlers should run
listener: Inline(listener.unwrap()),
});
}
}
}
}
fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener> {
let entries = self.handlers.find(&ty);
entries.and_then(|entries| entries.iter().find(|entry| {
match entry.listener {
Inline(_) => true,
_ => false,
}
}).map(|entry| entry.listener.get_listener()))
}
fn set_event_handler_common(&mut self, ty: &str, listener: *mut JSObject) {
let listener = EventListener::new(listener);
self.set_inline_event_listener(ty.to_owned(), Some(listener));
}
fn get_event_handler_common(&self, ty: &str) -> *mut JSObject {
let listener = self.get_inline_event_listener(ty.to_owned());
listener.map(|listener| listener.parent.callback()).unwrap_or(ptr::mut_null())
}
} }
pub trait EventTargetMethods { pub trait EventTargetMethods {
@ -104,7 +178,7 @@ impl<'a> EventTargetMethods for JSRef<'a, EventTarget> {
let phase = if capture { Capturing } else { Bubbling }; let phase = if capture { Capturing } else { Bubbling };
let new_entry = EventListenerEntry { let new_entry = EventListenerEntry {
phase: phase, phase: phase,
listener: listener listener: Additive(listener)
}; };
if entry.as_slice().position_elem(&new_entry).is_none() { if entry.as_slice().position_elem(&new_entry).is_none() {
entry.push(new_entry); entry.push(new_entry);
@ -122,7 +196,7 @@ impl<'a> EventTargetMethods for JSRef<'a, EventTarget> {
let phase = if capture { Capturing } else { Bubbling }; let phase = if capture { Capturing } else { Bubbling };
let old_entry = EventListenerEntry { let old_entry = EventListenerEntry {
phase: phase, phase: phase,
listener: listener listener: Additive(listener)
}; };
let position = entry.as_slice().position_elem(&old_entry); let position = entry.as_slice().position_elem(&old_entry);
for &position in position.iter() { for &position in position.iter() {

View file

@ -68,3 +68,4 @@ partial interface Document {
}; };
Document implements ParentNode; Document implements ParentNode;
Document implements GlobalEventHandlers;

View file

@ -0,0 +1,45 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* http://www.whatwg.org/specs/web-apps/current-work/#eventhandler
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
//[TreatNonObjectAsNull] //XXXjdm webidl.py assertion
callback EventHandlerNonNull = any (Event event);
typedef EventHandlerNonNull? EventHandler;
//[TreatNonObjectAsNull] //XXXjdm webidl.py assertion
callback OnErrorEventHandlerNonNull = boolean ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error);
typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
[NoInterfaceObject]
interface GlobalEventHandlers {
attribute EventHandler onload;
};
[NoInterfaceObject]
interface WindowEventHandlers {
attribute EventHandler onunload;
};
// The spec has |attribute OnErrorEventHandler onerror;| on
// GlobalEventHandlers, and calls the handler differently depending on
// whether an ErrorEvent was fired. We don't do that, and until we do we'll
// need to distinguish between onerror on Window or on nodes.
[NoInterfaceObject]
interface OnErrorEventHandlerForNodes {
attribute EventHandler onerror;
};
[NoInterfaceObject]
interface OnErrorEventHandlerForWindow {
attribute OnErrorEventHandler onerror;
};

View file

@ -84,6 +84,9 @@ interface WindowTimers {
void clearInterval(optional long handle = 0);*/ void clearInterval(optional long handle = 0);*/
}; };
Window implements WindowTimers; Window implements WindowTimers;
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
Window implements OnErrorEventHandlerForWindow;
// Proprietary extensions. // Proprietary extensions.
partial interface Window { partial interface Window {

View file

@ -3,13 +3,14 @@
* 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::bindings::codegen::BindingDeclarations::WindowBinding; use dom::bindings::codegen::BindingDeclarations::WindowBinding;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable}; use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable};
use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::trace::{Traceable, Untraceable};
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::utils::{Reflectable, Reflector};
use dom::browsercontext::BrowserContext; use dom::browsercontext::BrowserContext;
use dom::document::Document; use dom::document::Document;
use dom::element::Element; use dom::element::Element;
use dom::eventtarget::{EventTarget, WindowTypeId}; use dom::eventtarget::{EventTarget, WindowTypeId, EventTargetHelpers};
use dom::console::Console; use dom::console::Console;
use dom::location::Location; use dom::location::Location;
use dom::navigator::Navigator; use dom::navigator::Navigator;
@ -23,7 +24,7 @@ use servo_util::str::DOMString;
use servo_util::task::{spawn_named}; use servo_util::task::{spawn_named};
use servo_util::url::parse_url; use servo_util::url::parse_url;
use js::jsapi::JSContext; use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::{NullValue, JSVal}; use js::jsval::{NullValue, JSVal};
@ -140,6 +141,12 @@ pub trait WindowMethods {
fn Window(&self) -> Temporary<Window>; fn Window(&self) -> Temporary<Window>;
fn Self(&self) -> Temporary<Window>; fn Self(&self) -> Temporary<Window>;
fn Performance(&mut self) -> Temporary<Performance>; fn Performance(&mut self) -> Temporary<Performance>;
fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject;
fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
fn GetOnunload(&self, _cx: *mut JSContext) -> *mut JSObject;
fn SetOnunload(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
fn GetOnerror(&self, _cx: *mut JSContext) -> *mut JSObject;
fn SetOnerror(&mut self, _cx: *mut JSContext, listener: *mut JSObject);
fn Debug(&self, message: DOMString); fn Debug(&self, message: DOMString);
fn Gc(&self); fn Gc(&self);
} }
@ -268,6 +275,36 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
Temporary::new(self.performance.get_ref().clone()) Temporary::new(self.performance.get_ref().clone())
} }
fn GetOnload(&self, _cx: *mut JSContext) -> *mut JSObject {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("load")
}
fn SetOnload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("load", listener)
}
fn GetOnunload(&self, _cx: *mut JSContext) -> *mut JSObject {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("unload")
}
fn SetOnunload(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("unload", listener)
}
fn GetOnerror(&self, _cx: *mut JSContext) -> *mut JSObject {
let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
eventtarget.get_event_handler_common("error")
}
fn SetOnerror(&mut self, _cx: *mut JSContext, listener: *mut JSObject) {
let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
eventtarget.set_event_handler_common("error", listener)
}
fn Debug(&self, message: DOMString) { fn Debug(&self, message: DOMString) {
debug!("{:s}", message); debug!("{:s}", message);
} }
@ -392,7 +429,6 @@ impl<'a> PrivateWindowHelpers for JSRef<'a, Window> {
handle handle
} }
} }
impl Window { impl Window {
pub fn new(cx: *mut JSContext, pub fn new(cx: *mut JSContext,
page: Rc<Page>, page: Rc<Page>,

View file

@ -4,13 +4,25 @@
</head> </head>
<body> <body>
<script> <script>
addEventListener("load", function(ev) { var onloads = 0;
function check(ev) {
is_a(ev, Event); is_a(ev, Event);
ev.preventDefault(); ev.preventDefault();
is(ev.defaultPrevented, false); is(ev.defaultPrevented, false);
is(ev.target, document); is(ev.target, document);
is(ev.currentTarget, window); is(ev.currentTarget, window);
if (onloads == 2) {
finish(); finish();
}
}
window.onload = function(ev) {
onloads++;
check(ev);
}
addEventListener("load", function(ev) {
onloads++;
check(ev);
}); });
</script> </script>
</body> </body>