aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/document.rs1
-rw-r--r--components/script/dom/eventtarget.rs103
-rw-r--r--components/script/dom/htmlbodyelement.rs29
-rw-r--r--components/script/dom/htmlelement.rs1
-rw-r--r--components/script/dom/macros.rs11
-rw-r--r--components/script/dom/webidls/EventHandler.webidl16
-rw-r--r--components/script/dom/webidls/Window.webidl1
-rw-r--r--components/script/dom/window.rs3
8 files changed, 118 insertions, 47 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 262e5a8b4d5..05bc4bffc21 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -9,6 +9,7 @@ use dom::bindings::codegen::Bindings::DocumentBinding;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index 84f59d8c498..0b53d3c43b2 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -2,19 +2,26 @@
* 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::callback::{CallbackContainer, ExceptionHandling};
+use dom::bindings::callback::{CallbackContainer, ExceptionHandling, CallbackFunction};
use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
+use dom::bindings::codegen::UnionTypes::EventOrString;
use dom::bindings::error::{Error, Fallible, report_pending_exception};
-use dom::bindings::inheritance::EventTargetTypeId;
+use dom::bindings::global::global_root_from_reflector;
+use dom::bindings::inheritance::{Castable, EventTargetTypeId};
+use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector};
+use dom::errorevent::ErrorEvent;
use dom::event::Event;
use dom::eventdispatcher::dispatch_event;
use dom::virtualmethods::VirtualMethods;
+use dom::window::Window;
use fnv::FnvHasher;
-use js::jsapi::{CompileFunction, JS_GetFunctionObject};
+use js::jsapi::{CompileFunction, JS_GetFunctionObject, RootedValue};
use js::jsapi::{HandleObject, JSContext, RootedFunction};
use js::jsapi::{JSAutoCompartment, JSAutoRequest};
use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
@@ -31,7 +38,20 @@ use url::Url;
use util::mem::HeapSizeOf;
use util::str::DOMString;
-pub type EventHandler = EventHandlerNonNull;
+#[derive(PartialEq, Clone, JSTraceable)]
+pub enum CommonEventHandler {
+ EventHandler(Rc<EventHandlerNonNull>),
+ ErrorEventHandler(Rc<OnErrorEventHandlerNonNull>),
+}
+
+impl CommonEventHandler {
+ fn parent(&self) -> &CallbackFunction {
+ match *self {
+ CommonEventHandler::EventHandler(ref handler) => &handler.parent,
+ CommonEventHandler::ErrorEventHandler(ref handler) => &handler.parent,
+ }
+ }
+}
#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum ListenerPhase {
@@ -78,7 +98,7 @@ impl EventTargetTypeId {
#[derive(JSTraceable, Clone, PartialEq)]
pub enum EventListenerType {
Additive(Rc<EventListener>),
- Inline(Rc<EventHandler>),
+ Inline(CommonEventHandler),
}
impl HeapSizeOf for EventListenerType {
@@ -89,18 +109,45 @@ impl HeapSizeOf for EventListenerType {
}
impl EventListenerType {
+ // https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm
pub fn call_or_handle_event<T: Reflectable>(&self,
object: &T,
event: &Event,
exception_handle: ExceptionHandling) {
+ // Step 3
match *self {
EventListenerType::Additive(ref listener) => {
let _ = listener.HandleEvent_(object, event, exception_handle);
},
EventListenerType::Inline(ref handler) => {
- let _ = handler.Call_(object, event, exception_handle);
+ match *handler {
+ CommonEventHandler::ErrorEventHandler(ref handler) => {
+ if let Some(event) = event.downcast::<ErrorEvent>() {
+ let global = global_root_from_reflector(object);
+ let cx = global.r().get_cx();
+ let error = RootedValue::new(cx, event.Error(cx));
+ let _ = handler.Call_(object,
+ EventOrString::eString(event.Message()),
+ Some(event.Filename()),
+ Some(event.Lineno()),
+ Some(event.Colno()),
+ Some(error.handle()),
+ exception_handle);
+ return;
+ }
+
+ let _ = handler.Call_(object, EventOrString::eEvent(Root::from_ref(event)),
+ None, None, None, None, exception_handle);
+ }
+
+ CommonEventHandler::EventHandler(ref handler) => {
+ let _ = handler.Call_(object, event, exception_handle);
+ }
+ }
},
}
+
+ // TODO(#8490): step 4 (cancel event based on return value)
}
}
@@ -151,7 +198,7 @@ impl EventTarget {
pub fn set_inline_event_listener(&self,
ty: Atom,
- listener: Option<Rc<EventHandler>>) {
+ listener: Option<CommonEventHandler>) {
let mut handlers = self.handlers.borrow_mut();
let entries = match handlers.entry(ty) {
Occupied(entry) => entry.into_mut(),
@@ -185,7 +232,7 @@ impl EventTarget {
}
}
- pub fn get_inline_event_listener(&self, ty: &Atom) -> Option<Rc<EventHandler>> {
+ pub fn get_inline_event_listener(&self, ty: &Atom) -> Option<CommonEventHandler> {
let handlers = self.handlers.borrow();
let entries = handlers.get(ty);
entries.and_then(|entries| entries.iter().filter_map(|entry| {
@@ -197,6 +244,7 @@ impl EventTarget {
}
#[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
pub fn set_event_handler_uncompiled(&self,
cx: *mut JSContext,
url: Url,
@@ -207,8 +255,21 @@ impl EventTarget {
let name = CString::new(ty).unwrap();
let lineno = 0; //XXXjdm need to get a real number here
- let nargs = 1; //XXXjdm not true for onerror
static mut ARG_NAMES: [*const c_char; 1] = [b"event\0" as *const u8 as *const c_char];
+ static mut ERROR_ARG_NAMES: [*const c_char; 5] = [b"event\0" as *const u8 as *const c_char,
+ b"source\0" as *const u8 as *const c_char,
+ b"lineno\0" as *const u8 as *const c_char,
+ b"colno\0" as *const u8 as *const c_char,
+ b"error\0" as *const u8 as *const c_char];
+ // step 10
+ let is_error = ty == "error" && self.is::<Window>();
+ let args = unsafe {
+ if is_error {
+ &ERROR_ARG_NAMES[..]
+ } else {
+ &ARG_NAMES[..]
+ }
+ };
let source: Vec<u16> = source.utf16_units().collect();
let options = CompileOptionsWrapper::new(cx, url.as_ptr(), lineno);
@@ -222,8 +283,8 @@ impl EventTarget {
scopechain.ptr,
options.ptr,
name.as_ptr(),
- nargs,
- ARG_NAMES.as_mut_ptr(),
+ args.len() as u32,
+ args.as_ptr(),
source.as_ptr(),
source.len() as size_t,
handler.handle_mut())
@@ -235,20 +296,34 @@ impl EventTarget {
let funobj = unsafe { JS_GetFunctionObject(handler.ptr) };
assert!(!funobj.is_null());
- self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)));
+ if is_error {
+ self.set_error_event_handler(ty, Some(OnErrorEventHandlerNonNull::new(funobj)));
+ } else {
+ self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)));
+ }
}
pub fn set_event_handler_common<T: CallbackContainer>(
&self, ty: &str, listener: Option<Rc<T>>)
{
let event_listener = listener.map(|listener|
- EventHandlerNonNull::new(listener.callback()));
+ CommonEventHandler::EventHandler(
+ EventHandlerNonNull::new(listener.callback())));
+ self.set_inline_event_listener(Atom::from_slice(ty), event_listener);
+ }
+
+ pub fn set_error_event_handler<T: CallbackContainer>(
+ &self, ty: &str, listener: Option<Rc<T>>)
+ {
+ let event_listener = listener.map(|listener|
+ CommonEventHandler::ErrorEventHandler(
+ OnErrorEventHandlerNonNull::new(listener.callback())));
self.set_inline_event_listener(Atom::from_slice(ty), event_listener);
}
pub fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>> {
let listener = self.get_inline_event_listener(&Atom::from_slice(ty));
- listener.map(|listener| CallbackContainer::new(listener.parent.callback()))
+ listener.map(|listener| CallbackContainer::new(listener.parent().callback()))
}
pub fn has_handlers(&self) -> bool {
diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs
index 80c3098e62f..a3c53071134 100644
--- a/components/script/dom/htmlbodyelement.rs
+++ b/components/script/dom/htmlbodyelement.rs
@@ -153,34 +153,43 @@ impl VirtualMethods for HTMLBodyElement {
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
- self.super_type().unwrap().attribute_mutated(attr, mutation);
- match (attr.local_name(), mutation) {
+ let do_super_mutate = match (attr.local_name(), mutation) {
(&atom!(background), _) => {
*self.background.borrow_mut() = mutation.new_value(attr).and_then(|value| {
let document = document_from_node(self);
let base = document.url();
UrlParser::new().base_url(&base).parse(&value).ok()
});
+ true
},
(name, AttributeMutation::Set(_)) if name.starts_with("on") => {
let window = window_from_node(self);
let (cx, url, reflector) = (window.get_cx(),
window.get_url(),
window.reflector().get_jsobject());
- let evtarget = match name {
+ // https://html.spec.whatwg.org/multipage/
+ // #event-handlers-on-elements,-document-objects,-and-window-objects:event-handlers-3
+ match name {
&atom!(onfocus) | &atom!(onload) | &atom!(onscroll) | &atom!(onafterprint) |
&atom!(onbeforeprint) | &atom!(onbeforeunload) | &atom!(onhashchange) |
&atom!(onlanguagechange) | &atom!(onmessage) | &atom!(onoffline) | &atom!(ononline) |
&atom!(onpagehide) | &atom!(onpageshow) | &atom!(onpopstate) | &atom!(onstorage) |
&atom!(onresize) | &atom!(onunload) | &atom!(onerror)
- => window.upcast::<EventTarget>(), // forwarded event
- _ => self.upcast::<EventTarget>(),
- };
- evtarget.set_event_handler_uncompiled(cx, url, reflector,
- &name[2..],
- DOMString((**attr.value()).to_owned()));
+ => {
+ let evtarget = window.upcast::<EventTarget>(); // forwarded event
+ evtarget.set_event_handler_uncompiled(cx, url, reflector,
+ &name[2..],
+ DOMString((**attr.value()).to_owned()));
+ false
+ }
+ _ => true, // HTMLElement::attribute_mutated will take care of this.
+ }
},
- _ => {}
+ _ => true,
+ };
+
+ if do_super_mutate {
+ self.super_type().unwrap().attribute_mutated(attr, mutation);
}
}
}
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index ffb31eca194..8b40ca4e5b1 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -6,6 +6,7 @@ use dom::attr::Attr;
use dom::attr::AttrValue;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLElementBinding;
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index a029593b0e1..370621dfe8d 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -279,7 +279,7 @@ macro_rules! no_jsmanaged_fields(
/// These are used to generate a event handler which has no special case.
macro_rules! define_event_handler(
- ($handler: ident, $event_type: ident, $getter: ident, $setter: ident) => (
+ ($handler: ident, $event_type: ident, $getter: ident, $setter: ident, $setter_fn: ident) => (
fn $getter(&self) -> Option<::std::rc::Rc<$handler>> {
use dom::bindings::inheritance::Castable;
use dom::eventtarget::EventTarget;
@@ -291,20 +291,22 @@ macro_rules! define_event_handler(
use dom::bindings::inheritance::Castable;
use dom::eventtarget::EventTarget;
let eventtarget = self.upcast::<EventTarget>();
- eventtarget.set_event_handler_common(stringify!($event_type), listener)
+ eventtarget.$setter_fn(stringify!($event_type), listener)
}
)
);
macro_rules! event_handler(
($event_type: ident, $getter: ident, $setter: ident) => (
- define_event_handler!(EventHandlerNonNull, $event_type, $getter, $setter);
+ define_event_handler!(EventHandlerNonNull, $event_type, $getter, $setter,
+ set_event_handler_common);
)
);
macro_rules! error_event_handler(
($event_type: ident, $getter: ident, $setter: ident) => (
- define_event_handler!(OnErrorEventHandlerNonNull, $event_type, $getter, $setter);
+ define_event_handler!(OnErrorEventHandlerNonNull, $event_type, $getter, $setter,
+ set_error_event_handler);
)
);
@@ -319,6 +321,7 @@ macro_rules! global_event_handlers(
);
(NoOnload) => (
event_handler!(click, GetOnclick, SetOnclick);
+ error_event_handler!(error, GetOnerror, SetOnerror);
event_handler!(keydown, GetOnkeydown, SetOnkeydown);
event_handler!(keypress, GetOnkeypress, SetOnkeypress);
event_handler!(keyup, GetOnkeyup, SetOnkeyup);
diff --git a/components/script/dom/webidls/EventHandler.webidl b/components/script/dom/webidls/EventHandler.webidl
index 7ff237f2ceb..c077db5e4b7 100644
--- a/components/script/dom/webidls/EventHandler.webidl
+++ b/components/script/dom/webidls/EventHandler.webidl
@@ -24,6 +24,7 @@ typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
[NoInterfaceObject]
interface GlobalEventHandlers {
attribute EventHandler onclick;
+ attribute OnErrorEventHandler onerror;
attribute EventHandler onload;
attribute EventHandler oninput;
attribute EventHandler onkeydown;
@@ -38,18 +39,3 @@ interface WindowEventHandlers {
attribute EventHandler onunload;
attribute EventHandler onstorage;
};
-
-// 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;
-};
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index 4f461f1a9a6..82a2f3fd34f 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -161,7 +161,6 @@ partial interface Window {
void gc();
void trap();
};
-Window implements OnErrorEventHandlerForWindow;
// WebDriver extensions
partial interface Window {
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 09f14f12510..5a914fcc49d 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -511,9 +511,6 @@ impl WindowMethods for Window {
// https://html.spec.whatwg.org/multipage/#handler-window-onstorage
event_handler!(storage, GetOnstorage, SetOnstorage);
- // https://html.spec.whatwg.org/multipage/#handler-onerror
- error_event_handler!(error, GetOnerror, SetOnerror);
-
// https://developer.mozilla.org/en-US/docs/Web/API/Window/screen
fn Screen(&self) -> Root<Screen> {
self.screen.or_init(|| Screen::new(self))