Add cleanup code to web backend, mostly web-sys (#1715)

* web-sys: Impl. event listeners removal for canvas

* web-sys: Impl. media query listeners cleanup

* web: Emit WindowEvent::Destroyed after Window is dropped

* web-sys: Fix unload event closure being dropped early

* web: Impl. cleanup on ControlFlow::Exit

- Drops the Runner, which causes the event handler closure to be
  dropped.
- (web-sys only:) Remove event listeners from DOM.

* web: Do not remove canvas from DOM when dropping Window

The canvas was inserted by the user, so it should be up to the user
whether the canvas should be removed.

* Update changelog
This commit is contained in:
alvinhochun 2020-09-21 06:42:07 +08:00 committed by GitHub
parent 1c97a310b1
commit 47e7aa4209
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 436 additions and 162 deletions

View file

@ -0,0 +1,65 @@
use wasm_bindgen::{prelude::Closure, JsCast};
use web_sys::{AddEventListenerOptions, EventTarget};
pub(super) struct EventListenerHandle<T: ?Sized> {
target: EventTarget,
event_type: &'static str,
listener: Closure<T>,
}
impl<T: ?Sized> EventListenerHandle<T> {
pub fn new<U>(target: &U, event_type: &'static str, listener: Closure<T>) -> Self
where
U: Clone + Into<EventTarget>,
{
let target = target.clone().into();
target
.add_event_listener_with_callback(event_type, listener.as_ref().unchecked_ref())
.expect("Failed to add event listener");
EventListenerHandle {
target,
event_type,
listener,
}
}
pub fn with_options<U>(
target: &U,
event_type: &'static str,
listener: Closure<T>,
options: &AddEventListenerOptions,
) -> Self
where
U: Clone + Into<EventTarget>,
{
let target = target.clone().into();
target
.add_event_listener_with_callback_and_add_event_listener_options(
event_type,
listener.as_ref().unchecked_ref(),
options,
)
.expect("Failed to add event listener");
EventListenerHandle {
target,
event_type,
listener,
}
}
}
impl<T: ?Sized> Drop for EventListenerHandle<T> {
fn drop(&mut self) {
self.target
.remove_event_listener_with_callback(
self.event_type,
self.listener.as_ref().unchecked_ref(),
)
.unwrap_or_else(|e| {
web_sys::console::error_2(
&format!("Error removing event listener {}", self.event_type).into(),
&e,
)
});
}
}