seed/browser/dom/
event_handler.rs

1//! This module contains code related to event handling; ie things that update the dom, related to
2//! `web_sys::Event`
3
4use super::super::util;
5use crate::virtual_dom::{Ev, EventHandler};
6use std::rc::Rc;
7use wasm_bindgen::JsCast;
8
9/// Create an event that passes a String of field text, for fast input handling.
10#[allow(clippy::shadow_unrelated)]
11#[allow(clippy::missing_panics_doc)]
12pub fn input_ev<Ms: 'static, MsU: 'static>(
13    trigger: impl Into<Ev>,
14    handler: impl FnOnce(String) -> MsU + 'static + Clone,
15) -> EventHandler<Ms> {
16    let handler = map_callback_return_to_option_ms!(
17        dyn Fn(String) -> Option<Ms>,
18        handler.clone(),
19        "Handler can return only Msg, Option<Msg> or ()!",
20        Rc
21    );
22    let handler = move |event: web_sys::Event| {
23        let value = event
24            .target()
25            .as_ref()
26            .ok_or("Can't get event target reference")
27            .and_then(util::get_value)
28            .map_err(crate::error)
29            .unwrap_or_default();
30        handler(value)
31    };
32    EventHandler::new(trigger, handler)
33}
34
35/// Create an event that passes a `web_sys::KeyboardEvent`, allowing easy access
36/// to items like `key_code`() and key().
37#[allow(clippy::shadow_unrelated)]
38#[allow(clippy::missing_panics_doc)]
39pub fn keyboard_ev<Ms: 'static, MsU: 'static>(
40    trigger: impl Into<Ev>,
41    handler: impl FnOnce(web_sys::KeyboardEvent) -> MsU + 'static + Clone,
42) -> EventHandler<Ms> {
43    let handler = map_callback_return_to_option_ms!(
44        dyn Fn(web_sys::KeyboardEvent) -> Option<Ms>,
45        handler.clone(),
46        "Handler can return only Msg, Option<Msg> or ()!",
47        Rc
48    );
49    let handler = move |event: web_sys::Event| {
50        handler(event.dyn_ref::<web_sys::KeyboardEvent>().unwrap().clone())
51    };
52    EventHandler::new(trigger, handler)
53}
54
55/// See `keyboard_ev`
56#[allow(clippy::shadow_unrelated)]
57#[allow(clippy::missing_panics_doc)]
58pub fn mouse_ev<Ms: 'static, MsU: 'static>(
59    trigger: impl Into<Ev>,
60    handler: impl FnOnce(web_sys::MouseEvent) -> MsU + 'static + Clone,
61) -> EventHandler<Ms> {
62    let handler = map_callback_return_to_option_ms!(
63        dyn Fn(web_sys::MouseEvent) -> Option<Ms>,
64        handler.clone(),
65        "Handler can return only Msg, Option<Msg> or ()!",
66        Rc
67    );
68    let handler = move |event: web_sys::Event| {
69        handler(event.dyn_ref::<web_sys::MouseEvent>().unwrap().clone())
70    };
71    EventHandler::new(trigger, handler)
72}
73
74/// See `keyboard_ev`
75#[allow(clippy::shadow_unrelated)]
76#[allow(clippy::missing_panics_doc)]
77pub fn touch_ev<Ms: 'static, MsU: 'static>(
78    trigger: impl Into<Ev>,
79    handler: impl FnOnce(web_sys::TouchEvent) -> MsU + 'static + Clone,
80) -> EventHandler<Ms> {
81    let handler = map_callback_return_to_option_ms!(
82        dyn Fn(web_sys::TouchEvent) -> Option<Ms>,
83        handler.clone(),
84        "Handler can return only Msg, Option<Msg> or ()!",
85        Rc
86    );
87    let handler = move |event: web_sys::Event| {
88        handler(event.dyn_ref::<web_sys::TouchEvent>().unwrap().clone())
89    };
90    EventHandler::new(trigger, handler)
91}
92
93/// See `keyboard_ev`
94#[allow(clippy::shadow_unrelated)]
95#[allow(clippy::missing_panics_doc)]
96pub fn drag_ev<Ms: 'static, MsU: 'static>(
97    trigger: impl Into<Ev>,
98    handler: impl FnOnce(web_sys::DragEvent) -> MsU + 'static + Clone,
99) -> EventHandler<Ms> {
100    let handler = map_callback_return_to_option_ms!(
101        dyn Fn(web_sys::DragEvent) -> Option<Ms>,
102        handler.clone(),
103        "Handler can return only Msg, Option<Msg> or ()!",
104        Rc
105    );
106    let handler = move |event: web_sys::Event| {
107        handler(event.dyn_ref::<web_sys::DragEvent>().unwrap().clone())
108    };
109    EventHandler::new(trigger, handler)
110}
111
112/// See `keyboard_ev`
113#[allow(clippy::shadow_unrelated)]
114#[allow(clippy::missing_panics_doc)]
115pub fn pointer_ev<Ms: 'static, MsU: 'static>(
116    trigger: impl Into<Ev>,
117    handler: impl FnOnce(web_sys::PointerEvent) -> MsU + 'static + Clone,
118) -> EventHandler<Ms> {
119    let handler = map_callback_return_to_option_ms!(
120        dyn Fn(web_sys::PointerEvent) -> Option<Ms>,
121        handler.clone(),
122        "Handler can return only Msg, Option<Msg> or ()!",
123        Rc
124    );
125    let handler = move |event: web_sys::Event| {
126        handler(event.dyn_ref::<web_sys::PointerEvent>().unwrap().clone())
127    };
128    EventHandler::new(trigger, handler)
129}
130
131/// See `keyboard_ev`
132#[allow(clippy::shadow_unrelated)]
133#[allow(clippy::missing_panics_doc)]
134pub fn wheel_ev<Ms: 'static, MsU: 'static>(
135    trigger: impl Into<Ev>,
136    handler: impl FnOnce(web_sys::WheelEvent) -> MsU + 'static + Clone,
137) -> EventHandler<Ms> {
138    let handler = map_callback_return_to_option_ms!(
139        dyn Fn(web_sys::WheelEvent) -> Option<Ms>,
140        handler.clone(),
141        "Handler can return only Msg, Option<Msg> or ()!",
142        Rc
143    );
144    let handler = move |event: web_sys::Event| {
145        handler(event.dyn_ref::<web_sys::WheelEvent>().unwrap().clone())
146    };
147    EventHandler::new(trigger, handler)
148}
149
150/// Create an event that accepts a closure, and passes a `web_sys::Event`, allowing full control of
151/// event-handling.
152#[deprecated(since = "0.6.0", note = "Use `ev` instead.")]
153pub fn raw_ev<Ms: 'static, MsU: 'static>(
154    trigger: impl Into<Ev>,
155    handler: impl FnOnce(web_sys::Event) -> MsU + 'static + Clone,
156) -> EventHandler<Ms> {
157    ev(trigger, handler)
158}
159
160/// Create an event handler that accepts a closure, and passes a `web_sys::Event`, allowing full control of
161/// event-handling.
162///
163/// Handler has to return `Msg`, `Option<Msg>` or `()`.
164///
165/// # Panics
166///
167/// Panics when the handler doesn't return `Msg` or `()`. (It will be changed to a compile-time error).
168#[allow(clippy::shadow_unrelated)]
169#[allow(clippy::missing_panics_doc)]
170pub fn ev<Ms: 'static, MsU: 'static>(
171    trigger: impl Into<Ev>,
172    handler: impl FnOnce(web_sys::Event) -> MsU + 'static + Clone,
173) -> EventHandler<Ms> {
174    let handler = map_callback_return_to_option_ms!(
175        dyn Fn(web_sys::Event) -> Option<Ms>,
176        handler.clone(),
177        "Handler can return only Msg, Option<Msg> or ()!",
178        Rc
179    );
180    #[allow(clippy::redundant_closure)]
181    EventHandler::new(trigger, move |event| handler(event))
182}
183
184/// Create an event that passes no data, other than it occurred. Foregoes using a closure,
185/// in favor of pointing to a message directly.
186#[deprecated(since = "0.8.0", note = "Use `ev` instead.")]
187pub fn simple_ev<Ms: Clone + 'static>(trigger: impl Into<Ev>, message: Ms) -> EventHandler<Ms> {
188    let handler = || Some(message);
189    let closure_handler = move |_| handler.clone()();
190    EventHandler::new(trigger, closure_handler)
191}