servo/components/script/dom/eventtarget.rs

814 lines
29 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 https://mozilla.org/MPL/2.0/. */
use crate::dom::beforeunloadevent::BeforeUnloadEvent;
use crate::dom::bindings::callback::{CallbackContainer, CallbackFunction, ExceptionHandling};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEventMethods;
use crate::dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods;
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull;
use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use crate::dom::bindings::codegen::Bindings::EventTargetBinding::AddEventListenerOptions;
use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventListenerOptions;
use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::UnionTypes::AddEventListenerOptionsOrBoolean;
use crate::dom::bindings::codegen::UnionTypes::EventListenerOptionsOrBoolean;
use crate::dom::bindings::codegen::UnionTypes::EventOrString;
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, reflect_dom_object2, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::element::Element;
use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlformelement::FormControlElementHelpers;
use crate::dom::node::document_from_node;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::{enter_realm, InRealm};
use dom_struct::dom_struct;
use fnv::FnvHasher;
use js::jsapi::JS_GetFunctionObject;
use js::rust::transform_u16_to_source_text;
use js::rust::wrappers::CompileFunction;
use js::rust::{CompileOptionsWrapper, RootedObjectVectorWrapper, HandleObject};
use libc::c_char;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use std::default::Default;
use std::ffi::CString;
use std::hash::BuildHasherDefault;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
pub enum CommonEventHandler {
EventHandler(#[ignore_malloc_size_of = "Rc"] Rc<EventHandlerNonNull>),
ErrorEventHandler(#[ignore_malloc_size_of = "Rc"] Rc<OnErrorEventHandlerNonNull>),
BeforeUnloadEventHandler(#[ignore_malloc_size_of = "Rc"] Rc<OnBeforeUnloadEventHandlerNonNull>),
}
impl CommonEventHandler {
fn parent(&self) -> &CallbackFunction {
match *self {
CommonEventHandler::EventHandler(ref handler) => &handler.parent,
CommonEventHandler::ErrorEventHandler(ref handler) => &handler.parent,
CommonEventHandler::BeforeUnloadEventHandler(ref handler) => &handler.parent,
}
}
}
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum ListenerPhase {
Capturing,
Bubbling,
}
/// <https://html.spec.whatwg.org/multipage/#internal-raw-uncompiled-handler>
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
struct InternalRawUncompiledHandler {
source: DOMString,
url: ServoUrl,
line: usize,
}
/// A representation of an event handler, either compiled or uncompiled raw source, or null.
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
enum InlineEventListener {
Uncompiled(InternalRawUncompiledHandler),
Compiled(CommonEventHandler),
Null,
}
impl InlineEventListener {
/// Get a compiled representation of this event handler, compiling it from its
/// raw source if necessary.
/// <https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler>
fn get_compiled_handler(
&mut self,
owner: &EventTarget,
ty: &Atom,
) -> Option<CommonEventHandler> {
match mem::replace(self, InlineEventListener::Null) {
InlineEventListener::Null => None,
InlineEventListener::Uncompiled(handler) => {
let result = owner.get_compiled_event_handler(handler, ty);
if let Some(ref compiled) = result {
*self = InlineEventListener::Compiled(compiled.clone());
}
result
},
InlineEventListener::Compiled(handler) => {
*self = InlineEventListener::Compiled(handler.clone());
Some(handler)
},
}
}
}
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
enum EventListenerType {
Additive(#[ignore_malloc_size_of = "Rc"] Rc<EventListener>),
Inline(InlineEventListener),
}
impl EventListenerType {
fn get_compiled_listener(
&mut self,
owner: &EventTarget,
ty: &Atom,
) -> Option<CompiledEventListener> {
match self {
&mut EventListenerType::Inline(ref mut inline) => inline
.get_compiled_handler(owner, ty)
.map(CompiledEventListener::Handler),
&mut EventListenerType::Additive(ref listener) => {
Some(CompiledEventListener::Listener(listener.clone()))
},
}
}
}
/// A representation of an EventListener/EventHandler object that has previously
/// been compiled successfully, if applicable.
pub enum CompiledEventListener {
Listener(Rc<EventListener>),
Handler(CommonEventHandler),
}
impl CompiledEventListener {
#[allow(unsafe_code)]
pub fn associated_global(&self) -> DomRoot<GlobalScope> {
let obj = match self {
CompiledEventListener::Listener(listener) => listener.callback(),
CompiledEventListener::Handler(CommonEventHandler::EventHandler(handler)) => {
handler.callback()
},
CompiledEventListener::Handler(CommonEventHandler::ErrorEventHandler(handler)) => {
handler.callback()
},
CompiledEventListener::Handler(CommonEventHandler::BeforeUnloadEventHandler(
handler,
)) => handler.callback(),
};
unsafe { GlobalScope::from_object(obj) }
}
// https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm
pub fn call_or_handle_event(
&self,
object: &EventTarget,
event: &Event,
exception_handle: ExceptionHandling,
) {
// Step 3
match *self {
CompiledEventListener::Listener(ref listener) => {
let _ = listener.HandleEvent_(object, event, exception_handle);
},
CompiledEventListener::Handler(ref handler) => {
match *handler {
CommonEventHandler::ErrorEventHandler(ref handler) => {
if let Some(event) = event.downcast::<ErrorEvent>() {
if object.is::<Window>() || object.is::<WorkerGlobalScope>() {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let error = event.Error(cx));
let return_value = handler.Call_(
object,
EventOrString::String(event.Message()),
Some(event.Filename()),
Some(event.Lineno()),
Some(event.Colno()),
Some(error.handle()),
exception_handle,
);
// Step 4
if let Ok(return_value) = return_value {
rooted!(in(*cx) let return_value = return_value);
if return_value.handle().is_boolean() &&
return_value.handle().to_boolean() == true
{
event.upcast::<Event>().PreventDefault();
}
}
return;
}
}
let _ = handler.Call_(
object,
EventOrString::Event(DomRoot::from_ref(event)),
None,
None,
None,
None,
exception_handle,
);
},
CommonEventHandler::BeforeUnloadEventHandler(ref handler) => {
if let Some(event) = event.downcast::<BeforeUnloadEvent>() {
// Step 5
if let Ok(value) =
handler.Call_(object, event.upcast::<Event>(), exception_handle)
{
let rv = event.ReturnValue();
if let Some(v) = value {
if rv.is_empty() {
event.SetReturnValue(v);
}
event.upcast::<Event>().PreventDefault();
}
}
} else {
// Step 5, "Otherwise" clause
let _ =
handler.Call_(object, event.upcast::<Event>(), exception_handle);
}
},
CommonEventHandler::EventHandler(ref handler) => {
if let Ok(value) = handler.Call_(object, event, exception_handle) {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let value = value);
let value = value.handle();
//Step 5
let should_cancel = value.is_boolean() && value.to_boolean() == false;
if should_cancel {
// FIXME: spec says to set the cancelled flag directly
// here, not just to prevent default;
// can that ever make a difference?
event.PreventDefault();
}
}
},
}
},
}
}
}
// https://dom.spec.whatwg.org/#concept-event-listener
// (as distinct from https://dom.spec.whatwg.org/#callbackdef-eventlistener)
#[derive(Clone, DenyPublicFields, JSTraceable, MallocSizeOf)]
/// A listener in a collection of event listeners.
struct EventListenerEntry {
phase: ListenerPhase,
listener: EventListenerType,
once: bool,
}
impl std::cmp::PartialEq for EventListenerEntry {
fn eq(&self, other: &Self) -> bool {
self.phase == other.phase && self.listener == other.listener
}
}
#[derive(JSTraceable, MallocSizeOf)]
/// A mix of potentially uncompiled and compiled event listeners of the same type.
struct EventListeners(Vec<EventListenerEntry>);
impl Deref for EventListeners {
type Target = Vec<EventListenerEntry>;
fn deref(&self) -> &Vec<EventListenerEntry> {
&self.0
}
}
impl DerefMut for EventListeners {
fn deref_mut(&mut self) -> &mut Vec<EventListenerEntry> {
&mut self.0
}
}
impl EventListeners {
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
fn get_inline_listener(
&mut self,
owner: &EventTarget,
ty: &Atom,
) -> Option<CommonEventHandler> {
for entry in &mut self.0 {
if let EventListenerType::Inline(ref mut inline) = entry.listener {
// Step 1.1-1.8 and Step 2
return inline.get_compiled_handler(owner, ty);
}
}
// Step 2
None
}
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
fn get_listeners(
&mut self,
phase: Option<ListenerPhase>,
owner: &EventTarget,
ty: &Atom,
) -> Vec<CompiledEventListener> {
self.0
.iter_mut()
.filter_map(|entry| {
if phase.is_none() || Some(entry.phase) == phase {
// Step 1.1-1.8, 2
entry.listener.get_compiled_listener(owner, ty)
} else {
None
}
})
.collect()
}
fn has_listeners(&self) -> bool {
// TODO: add, and take into account, a 'removed' field?
// https://dom.spec.whatwg.org/#event-listener-removed
self.0.len() > 0
}
}
#[dom_struct]
pub struct EventTarget {
reflector_: Reflector,
handlers: DomRefCell<HashMap<Atom, EventListeners, BuildHasherDefault<FnvHasher>>>,
}
impl EventTarget {
pub fn new_inherited() -> EventTarget {
EventTarget {
reflector_: Reflector::new(),
handlers: DomRefCell::new(Default::default()),
}
}
fn new(global: &GlobalScope) -> DomRoot<EventTarget> {
reflect_dom_object(Box::new(EventTarget::new_inherited()), global)
}
#[allow(non_snake_case)]
pub fn Constructor(global: &GlobalScope, proto: HandleObject) -> Fallible<DomRoot<EventTarget>> {
Ok(reflect_dom_object2(Box::new(EventTarget::new_inherited()), global, proto))
}
pub fn has_listeners_for(&self, type_: &Atom) -> bool {
match self.handlers.borrow().get(type_) {
Some(listeners) => listeners.has_listeners(),
None => false,
}
}
pub fn get_listeners_for(
&self,
type_: &Atom,
specific_phase: Option<ListenerPhase>,
) -> Vec<CompiledEventListener> {
self.handlers
.borrow_mut()
.get_mut(type_)
.map_or(vec![], |listeners| {
listeners.get_listeners(specific_phase, self, type_)
})
}
pub fn dispatch_event(&self, event: &Event) -> EventStatus {
if let Some(window) = self.global().downcast::<Window>() {
if window.has_document() {
assert!(window.Document().can_invoke_script());
}
};
event.dispatch(self, false)
}
pub fn remove_all_listeners(&self) {
*self.handlers.borrow_mut() = Default::default();
}
/// <https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handlers-11>
fn set_inline_event_listener(&self, ty: Atom, listener: Option<InlineEventListener>) {
let mut handlers = self.handlers.borrow_mut();
let entries = match handlers.entry(ty) {
Occupied(entry) => entry.into_mut(),
Vacant(entry) => entry.insert(EventListeners(vec![])),
};
let idx = entries.iter().position(|ref entry| match entry.listener {
EventListenerType::Inline(_) => true,
_ => false,
});
match idx {
Some(idx) => match listener {
// Replace if there's something to replace with,
// but remove entirely if there isn't.
Some(listener) => {
entries[idx].listener = EventListenerType::Inline(listener);
},
None => {
entries.remove(idx);
},
},
None => {
if let Some(listener) = listener {
entries.push(EventListenerEntry {
phase: ListenerPhase::Bubbling,
listener: EventListenerType::Inline(listener),
once: false,
});
}
},
}
}
pub fn remove_listener_if_once(&self, ty: &Atom, listener: &Rc<EventListener>) {
let mut handlers = self.handlers.borrow_mut();
let listener = EventListenerType::Additive(listener.clone());
if let Some(entries) = handlers.get_mut(ty) {
entries.drain_filter(|e| e.listener == listener && e.once);
}
}
fn get_inline_event_listener(&self, ty: &Atom) -> Option<CommonEventHandler> {
let mut handlers = self.handlers.borrow_mut();
handlers
.get_mut(ty)
.and_then(|entry| entry.get_inline_listener(self, ty))
}
/// Store the raw uncompiled event handler for on-demand compilation later.
/// <https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handler-content-attributes-3>
pub fn set_event_handler_uncompiled(
&self,
url: ServoUrl,
line: usize,
ty: &str,
source: DOMString,
) {
let handler = InternalRawUncompiledHandler {
source: source,
line: line,
url: url,
};
self.set_inline_event_listener(
Atom::from(ty),
Some(InlineEventListener::Uncompiled(handler)),
);
}
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
// step 3
#[allow(unsafe_code)]
fn get_compiled_event_handler(
&self,
handler: InternalRawUncompiledHandler,
ty: &Atom,
) -> Option<CommonEventHandler> {
// Step 3.1
let element = self.downcast::<Element>();
let document = match element {
Some(element) => document_from_node(element),
None => self.downcast::<Window>().unwrap().Document(),
};
// Step 3.2
if !document.is_scripting_enabled() {
return None;
}
// Step 3.3
let body: Vec<u16> = handler.source.encode_utf16().collect();
// Step 3.4 is handler.line
// Step 3.5
let form_owner = element
.and_then(|e| e.as_maybe_form_control())
.and_then(|f| f.form_owner());
// Step 3.6 TODO: settings objects not implemented
// Step 3.7 is written as though we call the parser separately
// from the compiler; since we just call CompileFunction with
// source text, we handle parse errors later
// Step 3.8 TODO: settings objects not implemented
let window = document.window();
let _ac = enter_realm(&*window);
// Step 3.9
let name = CString::new(format!("on{}", &**ty)).unwrap();
// Step 3.9, subsection ParameterList
const ARG_NAMES: &[*const c_char] = &[b"event\0" as *const u8 as *const c_char];
const ERROR_ARG_NAMES: &[*const c_char] = &[
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,
];
let is_error = ty == &atom!("error") && self.is::<Window>();
let args = if is_error { ERROR_ARG_NAMES } else { ARG_NAMES };
let cx = GlobalScope::get_cx();
let options = unsafe {
CompileOptionsWrapper::new(*cx, &handler.url.to_string(), handler.line as u32)
};
// Step 3.9, subsection Scope steps 1-6
let scopechain = RootedObjectVectorWrapper::new(*cx);
if let Some(element) = element {
scopechain.append(document.reflector().get_jsobject().get());
if let Some(form_owner) = form_owner {
scopechain.append(form_owner.reflector().get_jsobject().get());
}
scopechain.append(element.reflector().get_jsobject().get());
}
rooted!(in(*cx) let mut handler = unsafe {
CompileFunction(
*cx,
scopechain.handle(),
options.ptr,
name.as_ptr(),
args.len() as u32,
args.as_ptr(),
&mut transform_u16_to_source_text(&body),
)
});
if handler.get().is_null() {
// Step 3.7
unsafe {
let ar = enter_realm(&*self);
// FIXME(#13152): dispatch error event.
report_pending_exception(*cx, false, InRealm::Entered(&ar));
}
return None;
}
// Step 3.10 happens when we drop _ac
// TODO Step 3.11
// Step 3.12
let funobj = unsafe { JS_GetFunctionObject(handler.get()) };
assert!(!funobj.is_null());
// Step 1.14
if is_error {
Some(CommonEventHandler::ErrorEventHandler(unsafe {
OnErrorEventHandlerNonNull::new(cx, funobj)
}))
} else {
if ty == &atom!("beforeunload") {
Some(CommonEventHandler::BeforeUnloadEventHandler(unsafe {
OnBeforeUnloadEventHandlerNonNull::new(cx, funobj)
}))
} else {
Some(CommonEventHandler::EventHandler(unsafe {
EventHandlerNonNull::new(cx, funobj)
}))
}
}
}
#[allow(unsafe_code)]
pub fn set_event_handler_common<T: CallbackContainer>(&self, ty: &str, listener: Option<Rc<T>>)
where
T: CallbackContainer,
{
let cx = GlobalScope::get_cx();
let event_listener = listener.map(|listener| {
InlineEventListener::Compiled(CommonEventHandler::EventHandler(unsafe {
EventHandlerNonNull::new(cx, listener.callback())
}))
});
self.set_inline_event_listener(Atom::from(ty), event_listener);
}
#[allow(unsafe_code)]
pub fn set_error_event_handler<T: CallbackContainer>(&self, ty: &str, listener: Option<Rc<T>>)
where
T: CallbackContainer,
{
let cx = GlobalScope::get_cx();
let event_listener = listener.map(|listener| {
InlineEventListener::Compiled(CommonEventHandler::ErrorEventHandler(unsafe {
OnErrorEventHandlerNonNull::new(cx, listener.callback())
}))
});
self.set_inline_event_listener(Atom::from(ty), event_listener);
}
#[allow(unsafe_code)]
pub fn set_beforeunload_event_handler<T: CallbackContainer>(
&self,
ty: &str,
listener: Option<Rc<T>>,
) where
T: CallbackContainer,
{
let cx = GlobalScope::get_cx();
let event_listener = listener.map(|listener| {
InlineEventListener::Compiled(CommonEventHandler::BeforeUnloadEventHandler(unsafe {
OnBeforeUnloadEventHandlerNonNull::new(cx, listener.callback())
}))
});
self.set_inline_event_listener(Atom::from(ty), event_listener);
}
#[allow(unsafe_code)]
pub fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<Rc<T>> {
let cx = GlobalScope::get_cx();
let listener = self.get_inline_event_listener(&Atom::from(ty));
unsafe {
listener.map(|listener| {
CallbackContainer::new(cx, listener.parent().callback_holder().get())
})
}
}
pub fn has_handlers(&self) -> bool {
!self.handlers.borrow().is_empty()
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(
name,
EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable,
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_bubbling_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(name, EventBubbles::Bubbles, EventCancelable::NotCancelable)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_cancelable_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(
name,
EventBubbles::DoesNotBubble,
EventCancelable::Cancelable,
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_bubbling_cancelable_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(name, EventBubbles::Bubbles, EventCancelable::Cancelable)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_event_with_params(
&self,
name: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable,
) -> DomRoot<Event> {
let event = Event::new(&self.global(), name, bubbles, cancelable);
event.fire(self);
event
}
// https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
pub fn add_event_listener(
&self,
ty: DOMString,
listener: Option<Rc<EventListener>>,
options: AddEventListenerOptions,
) {
let listener = match listener {
Some(l) => l,
None => return,
};
let mut handlers = self.handlers.borrow_mut();
let entry = match handlers.entry(Atom::from(ty)) {
Occupied(entry) => entry.into_mut(),
Vacant(entry) => entry.insert(EventListeners(vec![])),
};
let phase = if options.parent.capture {
ListenerPhase::Capturing
} else {
ListenerPhase::Bubbling
};
let new_entry = EventListenerEntry {
phase: phase,
listener: EventListenerType::Additive(listener),
once: options.once,
};
if !entry.contains(&new_entry) {
entry.push(new_entry);
}
}
// https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
pub fn remove_event_listener(
&self,
ty: DOMString,
listener: Option<Rc<EventListener>>,
options: EventListenerOptions,
) {
let ref listener = match listener {
Some(l) => l,
None => return,
};
let mut handlers = self.handlers.borrow_mut();
let entry = handlers.get_mut(&Atom::from(ty));
if let Some(entry) = entry {
let phase = if options.capture {
ListenerPhase::Capturing
} else {
ListenerPhase::Bubbling
};
let old_entry = EventListenerEntry {
phase: phase,
listener: EventListenerType::Additive(listener.clone()),
once: false,
};
if let Some(position) = entry.iter().position(|e| *e == old_entry) {
entry.remove(position);
}
}
}
}
impl EventTargetMethods for EventTarget {
// https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
fn AddEventListener(
&self,
ty: DOMString,
listener: Option<Rc<EventListener>>,
options: AddEventListenerOptionsOrBoolean,
) {
self.add_event_listener(ty, listener, options.into())
}
// https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
fn RemoveEventListener(
&self,
ty: DOMString,
listener: Option<Rc<EventListener>>,
options: EventListenerOptionsOrBoolean,
) {
self.remove_event_listener(ty, listener, options.into())
}
// https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
fn DispatchEvent(&self, event: &Event) -> Fallible<bool> {
if event.dispatching() || !event.initialized() {
return Err(Error::InvalidState);
}
event.set_trusted(false);
Ok(match self.dispatch_event(event) {
EventStatus::Canceled => false,
EventStatus::NotCanceled => true,
})
}
}
impl VirtualMethods for EventTarget {
fn super_type(&self) -> Option<&dyn VirtualMethods> {
None
}
}
impl From<AddEventListenerOptionsOrBoolean> for AddEventListenerOptions {
fn from(options: AddEventListenerOptionsOrBoolean) -> Self {
match options {
AddEventListenerOptionsOrBoolean::AddEventListenerOptions(options) => options,
AddEventListenerOptionsOrBoolean::Boolean(capture) => Self {
parent: EventListenerOptions { capture },
once: false,
},
}
}
}
impl From<EventListenerOptionsOrBoolean> for EventListenerOptions {
fn from(options: EventListenerOptionsOrBoolean) -> Self {
match options {
EventListenerOptionsOrBoolean::EventListenerOptions(options) => options,
EventListenerOptionsOrBoolean::Boolean(capture) => Self { capture },
}
}
}