ss_web_utils/
js.rs

1use std::fmt::{self, Debug};
2use std::convert::From;
3use std::hash::{Hash, Hasher};
4use std::iter::FromIterator;
5use std::collections::*;
6use std::cell::{self, Cell, RefCell};
7use std::rc::Rc;
8use std::any::Any;
9use serde::{self, Serialize, Deserialize, de::DeserializeOwned};
10use either::Either;
11use wasm_bindgen::JsValue;
12use wasm_bindgen::closure;
13use wasm_bindgen::closure::Closure;
14
15
16///////////////////////////////////////////////////////////////////////////////
17// CONSOLE
18///////////////////////////////////////////////////////////////////////////////
19pub mod console {
20    use super::*;
21    
22    pub fn log(value: impl Loggable) {
23        match value.to_js_value() {
24            Either::Left(x) => {
25                web_sys::console::log_1(&x);
26            }
27            Either::Right(x) => {
28                web_sys::console::log_1(x);
29            }
30        }
31    }
32    pub fn warn(value: impl Loggable) {
33        match value.to_js_value() {
34            Either::Left(x) => {
35                web_sys::console::warn_1(&x);
36            }
37            Either::Right(x) => {
38                web_sys::console::warn_1(x);
39            }
40        }
41    }
42    
43    pub trait Loggable {
44        fn to_js_value(&self) -> Either<JsValue, &JsValue>;
45    }
46    impl Loggable for &str {
47        fn to_js_value(&self) -> Either<JsValue, &JsValue> {
48            Either::Left(JsValue::from_str(self))
49        }
50    }
51    impl Loggable for String {
52        fn to_js_value(&self) -> Either<JsValue, &JsValue> {
53            Either::Left(JsValue::from_str(self.as_str()))
54        }
55    }
56    impl Loggable for JsValue {
57        fn to_js_value(&self) -> Either<JsValue, &JsValue> {
58            Either::Right(&self)
59        }
60    }
61    impl Loggable for &JsValue {
62        fn to_js_value(&self) -> Either<JsValue, &JsValue> {
63            Either::Right(self)
64        }
65    }
66}
67
68
69///////////////////////////////////////////////////////////////////////////////
70// JAVASCRIPT VOID CALLBACK
71///////////////////////////////////////////////////////////////////////////////
72
73
74#[derive(Clone)]
75pub struct VoidCallback {
76    pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
77    pub i_js_function: Rc<js_sys::Function>,
78}
79
80impl VoidCallback {
81    pub fn new(cb: Box<Fn(JsValue)>) -> Self {
82        use wasm_bindgen::JsCast;
83        let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
84            move |value: JsValue| {
85                cb(value)
86            }
87        }));
88        let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
89        let js_function: js_sys::Function = js_function.clone();
90        let void_callback = VoidCallback {
91            i_bindgen_closure: Rc::new(function_wrapper),
92            i_js_function: Rc::new(js_function),
93        };
94        void_callback
95    }
96}
97
98impl Debug for VoidCallback {
99    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
100        write!(f, "VoidCallback")
101    }
102}
103impl PartialEq for VoidCallback {
104    fn eq(&self, other: &VoidCallback) -> bool {true}
105}
106impl crate::dom::Callback for VoidCallback {
107    fn as_js_function(&self) -> &js_sys::Function {
108        self.i_js_function.as_ref()
109    }
110}
111
112///////////////////////////////////////////////////////////////////////////////
113// JAVASCRIPT QUEUE CALLBACK
114///////////////////////////////////////////////////////////////////////////////
115
116#[derive(Clone)]
117pub struct QueueCallback {
118    pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
119    pub i_js_function: Rc<js_sys::Function>,
120    pub i_events: Rc<RefCell<VecDeque<JsValue>>>,
121}
122
123impl QueueCallback {
124    pub fn new() -> Self {
125        use wasm_bindgen::JsCast;
126        let events_queue = Rc::new(RefCell::new(VecDeque::new()));
127        let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
128            let events_queue = events_queue.clone();
129            move |value: JsValue| {
130                events_queue.borrow_mut().push_back(value);
131            }
132        }));
133        let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
134        let js_function: js_sys::Function = js_function.clone();
135        let queue_callback = QueueCallback {
136            i_bindgen_closure: Rc::new(function_wrapper),
137            i_js_function: Rc::new(js_function),
138            i_events: events_queue,
139        };
140        queue_callback
141    }
142    pub fn drain(&self) -> Vec<JsValue> {
143        let xs: Vec<JsValue> = self.i_events.borrow_mut().drain(..).collect();
144        xs
145    }
146}
147
148impl Debug for QueueCallback {
149    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
150        write!(f, "QueueCallback")
151    }
152}
153impl PartialEq for QueueCallback {
154    fn eq(&self, other: &QueueCallback) -> bool {true}
155}
156
157impl crate::dom::Callback for QueueCallback {
158    fn as_js_function(&self) -> &js_sys::Function {
159        self.i_js_function.as_ref()
160    }
161}
162
163///////////////////////////////////////////////////////////////////////////////
164// JAVASCRIPT EVENT CALLBACK
165///////////////////////////////////////////////////////////////////////////////
166
167pub trait Handler<Msg> {
168    fn handler(&self, event: JsValue) -> Msg;
169}
170
171#[derive(Clone)]
172pub struct EventCallback<Msg> {
173    pub i_handler: Rc<Handler<Msg>>,
174    pub i_bindgen_closure: Rc<Closure<dyn Fn(JsValue)>>,
175    pub i_js_function: Rc<js_sys::Function>,
176    pub i_events: Rc<RefCell<VecDeque<JsValue>>>,
177}
178
179impl<Msg> EventCallback<Msg> {
180    pub fn new(handler: Rc<Handler<Msg>>) -> Self {
181        use wasm_bindgen::JsCast;
182        let events_queue = Rc::new(RefCell::new(VecDeque::new()));
183        let function_wrapper: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new({
184            let events_queue = events_queue.clone();
185            move |value: JsValue| {
186                events_queue.borrow_mut().push_back(value);
187            }
188        }));
189        let js_function: &js_sys::Function = function_wrapper.as_ref().unchecked_ref();
190        let js_function: js_sys::Function = js_function.clone();
191        let queue_callback = EventCallback {
192            i_handler: handler,
193            i_bindgen_closure: Rc::new(function_wrapper),
194            i_js_function: Rc::new(js_function),
195            i_events: events_queue,
196        };
197        queue_callback
198    }
199    // pub fn drain(&self) -> Vec<Msg> {
200    //     let xs: Vec<Msg> = self.i_events.borrow_mut()
201    //         .drain(..)
202    //         .map(|event| {
203    //             self.i_handler.as_ref().handler(event)
204    //         })
205    //         .collect();
206    //     xs
207    // }
208}
209
210impl<Msg> Debug for EventCallback<Msg> {
211    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
212        write!(f, "EventCallback")
213    }
214}
215impl<Msg> PartialEq for EventCallback<Msg> {
216    fn eq(&self, other: &EventCallback<Msg>) -> bool {true}
217}
218
219impl<Msg> crate::dom::Callback for EventCallback<Msg> {
220    fn as_js_function(&self) -> &js_sys::Function {
221        self.i_js_function.as_ref()
222    }
223}
224
225