1use crate::common::*;
2use js::*;
3use std::collections::HashMap;
4use std::sync::Arc;
5use std::sync::Mutex;
6
7pub fn query_selector(selector: &str) -> ExternRef {
8 let query_selector = js!(r#"
9 function(selector){
10 return document.querySelector(selector);
11 }"#);
12 query_selector.invoke_and_return_object(&[selector.into()])
13}
14
15pub fn element_set_inner_html(element: &ExternRef, html: &str) {
16 let set_inner_html = js!(r#"
17 function(element, html){
18 element.innerHTML = html;
19 }"#);
20 set_inner_html.invoke(&[element.into(), html.into()]);
21}
22
23pub fn element_add_class(element: &ExternRef, class: &str) {
24 let add_class = js!(r#"
25 function(element, class){
26 element.classList.add(class);
27 }"#);
28 add_class.invoke(&[element.into(), class.into()]);
29}
30
31pub fn element_remove_class(element: &ExternRef, class: &str) {
32 let remove_class = js!(r#"
33 function(element, class){
34 element.classList.remove(class);
35 }"#);
36 remove_class.invoke(&[element.into(), class.into()]);
37}
38
39pub fn element_set_style_attribute(element: &ExternRef, attribute: &str, value: &str) {
40 let set_style_attribute = js!(r#"
41 function(element, attribute, value){
42 element.style[attribute] = value;
43 }"#);
44 set_style_attribute.invoke(&[element.into(), attribute.into(), value.into()]);
45}
46
47pub fn element_set_attribute(element: &ExternRef, attribute: &str, value: &str) {
48 let set_attribute = js!(r#"
49 function(element, attribute, value){
50 element.setAttribute(attribute, value);
51 }"#);
52 set_attribute.invoke(&[element.into(), attribute.into(), value.into()]);
53}
54
55pub fn element_remove(element: &ExternRef) {
56 let remove = js!(r#"
57 function(element){
58 element.remove();
59 }"#);
60 remove.invoke(&[element.into()]);
61}
62
63pub struct ChangeEvent {
65 pub value: String,
66}
67
68static CHANGE_EVENT_HANDLERS: Mutex<
69 Option<HashMap<Arc<FunctionHandle>, Box<dyn FnMut(ChangeEvent) + Send + 'static>>>,
70> = Mutex::new(None);
71
72fn add_change_event_handler(
73 id: Arc<FunctionHandle>,
74 handler: Box<dyn FnMut(ChangeEvent) + Send + 'static>,
75) {
76 let mut handlers = CHANGE_EVENT_HANDLERS.lock().unwrap();
77 if let Some(h) = handlers.as_mut() {
78 h.insert(id, handler);
79 } else {
80 let mut h = HashMap::new();
81 h.insert(id, handler);
82 *handlers = Some(h);
83 }
84}
85
86fn remove_change_event_handler(id: &Arc<FunctionHandle>) {
87 let mut handlers = CHANGE_EVENT_HANDLERS.lock().unwrap();
88 if let Some(h) = handlers.as_mut() {
89 h.remove(id);
90 }
91}
92
93#[no_mangle]
94pub extern "C" fn web_handle_change_event(id: i64, allocation_id: usize) {
95 let mut handlers = CHANGE_EVENT_HANDLERS.lock().unwrap();
96 if let Some(h) = handlers.as_mut() {
97 for (key, handler) in h.iter_mut() {
98 if key.0.value == id {
99 let value = extract_string_from_memory(allocation_id);
100 handler(ChangeEvent { value });
101 }
102 }
103 }
104}
105
106pub fn add_change_event_listener(
107 element: &ExternRef,
108 handler: impl FnMut(ChangeEvent) + Send + 'static,
109) -> Arc<FunctionHandle> {
110 let function_ref = js!(r#"
111 function(element ){
112 const handler = (e) => {
113 const value = e.target.value;
114 const allocationId = this.writeUtf8ToMemory(value);
115 this.module.instance.exports.web_handle_change_event_handler(id, allocationId);
116 };
117 const id = this.storeObject(handler);
118 element.addEventListener("change",handler);
119 return id;
120 }"#)
121 .invoke_and_return_bigint(&[element.into()]);
122 let function_handle = Arc::new(FunctionHandle(ExternRef {
123 value: function_ref,
124 }));
125 add_change_event_handler(function_handle.clone(), Box::new(handler));
126 function_handle
127}
128
129pub fn element_remove_change_listener(element: &ExternRef, function_handle: &Arc<FunctionHandle>) {
130 let remove_change_listener = js!(r#"
131 function(element, f){
132 element.removeEventListener("change", f);
133 }"#);
134 remove_change_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
135 remove_change_event_handler(function_handle);
136}
137
138pub struct MouseEvent {
140 pub offset_x: f64,
141 pub offset_y: f64,
142}
143
144static MOUSE_EVENT_HANDLER: EventHandler<MouseEvent> = EventHandler {
145 listeners: Mutex::new(None),
146};
147
148#[no_mangle]
149pub extern "C" fn web_handle_mouse_event_handler(id: i64, x: f64, y: f64) {
150 MOUSE_EVENT_HANDLER.call(
151 id,
152 MouseEvent {
153 offset_x: x,
154 offset_y: y,
155 },
156 );
157}
158
159pub fn element_add_click_listener(
160 element: &ExternRef,
161 handler: impl FnMut(MouseEvent) + Send + 'static,
162) -> Arc<FunctionHandle> {
163 let function_ref = js!(r#"
164 function(element ){
165 const handler = (e) => {
166 this.module.instance.exports.web_handle_mouse_event_handler(id,e.offsetX, e.offsetY);
167 };
168 const id = this.storeObject(handler);
169 element.addEventListener("click",handler);
170 return id;
171 }"#).invoke_and_return_bigint(&[element.into()]);
172 let function_handle = Arc::new(FunctionHandle(ExternRef {
173 value: function_ref,
174 }));
175 MOUSE_EVENT_HANDLER.add_listener(function_handle.clone(), Box::new(handler));
176 function_handle
177}
178
179pub fn element_remove_click_listener(element: &ExternRef, function_handle: &Arc<FunctionHandle>) {
180 let remove_click_listener = js!(r#"
181 function(element, f){
182 element.removeEventListener("click", f);
183 }"#);
184 remove_click_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
185 MOUSE_EVENT_HANDLER.remove_listener(function_handle);
186}
187
188pub fn element_add_mouse_move_listener(
189 element: &ExternRef,
190 handler: impl FnMut(MouseEvent) + Send + 'static,
191) -> Arc<FunctionHandle> {
192 let function_ref = js!(r#"
193 function(element ){
194 const handler = (e) => {
195 this.module.instance.exports.web_handle_mouse_event_handler(id,e.offsetX, e.offsetY);
196 };
197 const id = this.storeObject(handler);
198 element.addEventListener("mousemove",handler);
199 return id;
200 }"#).invoke_and_return_bigint(&[element.into()]);
201 let function_handle = Arc::new(FunctionHandle(ExternRef {
202 value: function_ref,
203 }));
204 MOUSE_EVENT_HANDLER.add_listener(function_handle.clone(), Box::new(handler));
205 function_handle
206}
207
208pub fn element_remove_mouse_move_listener(
209 element: &ExternRef,
210 function_handle: &Arc<FunctionHandle>,
211) {
212 let remove_mouse_move_listener = js!(r#"
213 function(element, f){
214 element.removeEventListener("mousemove", f);
215 }"#);
216 remove_mouse_move_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
217 MOUSE_EVENT_HANDLER.remove_listener(function_handle);
218}
219
220pub fn element_add_mouse_down_listener(
221 element: &ExternRef,
222 handler: impl FnMut(MouseEvent) + Send + 'static,
223) -> Arc<FunctionHandle> {
224 let function_ref = js!(r#"
225 function(element ){
226 const handler = (e) => {
227 this.module.instance.exports.web_handle_mouse_event_handler(id,e.offsetX, e.offsetY);
228 };
229 const id = this.storeObject(handler);
230 element.addEventListener("mousedown",handler);
231 return id;
232 }"#).invoke_and_return_bigint(&[element.into()]);
233 let function_handle = Arc::new(FunctionHandle(ExternRef {
234 value: function_ref,
235 }));
236 MOUSE_EVENT_HANDLER.add_listener(function_handle.clone(), Box::new(handler));
237 function_handle
238}
239
240pub fn element_remove_mouse_down_listener(
241 element: &ExternRef,
242 function_handle: &Arc<FunctionHandle>,
243) {
244 let remove_mouse_down_listener = js!(r#"
245 function(element, f){
246 element.removeEventListener("mousedown", f);
247 }"#);
248 remove_mouse_down_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
249 MOUSE_EVENT_HANDLER.remove_listener(function_handle);
250}
251
252pub fn element_add_mouse_up_listener(
253 element: &ExternRef,
254 handler: impl FnMut(MouseEvent) + Send + 'static,
255) -> Arc<FunctionHandle> {
256 let function_ref = js!(r#"
257 function(element ){
258 const handler = (e) => {
259 this.module.instance.exports.web_handle_mouse_event_handler(id,e.offsetX, e.offsetY);
260 };
261 const id = this.storeObject(handler);
262 element.addEventListener("mouseup",handler);
263 return id;
264 }"#).invoke_and_return_bigint(&[element.into()]);
265 let function_handle = Arc::new(FunctionHandle(ExternRef {
266 value: function_ref,
267 }));
268 MOUSE_EVENT_HANDLER.add_listener(function_handle.clone(), Box::new(handler));
269 function_handle
270}
271
272pub fn element_remove_mouse_up_listener(
273 element: &ExternRef,
274 function_handle: &Arc<FunctionHandle>,
275) {
276 let remove_mouse_up_listener = js!(r#"
277 function(element, f){
278 element.removeEventListener("mouseup", f);
279 }"#);
280 remove_mouse_up_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
281 MOUSE_EVENT_HANDLER.remove_listener(function_handle);
282}
283
284pub struct KeyboardEvent {
287 pub key_code: f64,
288}
289
290static KEYBOARD_EVENT_HANDLERS: Mutex<
291 Option<HashMap<Arc<FunctionHandle>, Box<dyn FnMut(KeyboardEvent) + Send + 'static>>>,
292> = Mutex::new(None);
293
294fn add_keyboard_event_handler(
295 function_handle: Arc<FunctionHandle>,
296 handler: Box<dyn FnMut(KeyboardEvent) + Send + 'static>,
297) {
298 let mut h = KEYBOARD_EVENT_HANDLERS.lock().unwrap();
299 if h.is_none() {
300 *h = Some(HashMap::new());
301 }
302 h.as_mut().unwrap().insert(function_handle, handler);
303}
304
305fn remove_keyboard_event_handler(function_handle: &Arc<FunctionHandle>) {
306 let mut h = KEYBOARD_EVENT_HANDLERS.lock().unwrap();
307 if h.is_none() {
308 return;
309 }
310 h.as_mut().unwrap().remove(function_handle);
311}
312
313#[no_mangle]
314pub extern "C" fn web_handle_keyboard_event_handler(id: i64, key_code: f64) {
315 let mut handlers = KEYBOARD_EVENT_HANDLERS.lock().unwrap();
316 if let Some(h) = handlers.as_mut() {
317 for (key, handler) in h.iter_mut() {
318 if key.0.value == id {
319 handler(KeyboardEvent { key_code });
320 }
321 }
322 }
323}
324
325pub fn element_add_key_down_listener(
326 element: &ExternRef,
327 handler: impl FnMut(KeyboardEvent) + Send + 'static,
328) -> Arc<FunctionHandle> {
329 let function_ref = js!(r#"
330 function(element ){
331 const handler = (e) => {
332 this.module.instance.exports.web_handle_keyboard_event_handler(id,e.keyCode);
333 };
334 const id = this.storeObject(handler);
335 element.addEventListener("keydown",handler);
336 return id;
337 }"#)
338 .invoke_and_return_bigint(&[element.into()]);
339 let function_handle = Arc::new(FunctionHandle(ExternRef {
340 value: function_ref,
341 }));
342 add_keyboard_event_handler(function_handle.clone(), Box::new(handler));
343 function_handle
344}
345
346pub fn element_remove_key_down_listener(
347 element: &ExternRef,
348 function_handle: &Arc<FunctionHandle>,
349) {
350 let remove_key_down_listener = js!(r#"
351 function(element, f){
352 element.removeEventListener("keydown", f);
353 }"#);
354 remove_key_down_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
355 remove_keyboard_event_handler(function_handle);
356}
357
358pub fn element_add_key_up_listener(
359 element: &ExternRef,
360 handler: impl FnMut(KeyboardEvent) + Send + 'static,
361) -> Arc<FunctionHandle> {
362 let function_ref = js!(r#"
363 function(element ){
364 const handler = (e) => {
365 this.module.instance.exports.web_handle_keyboard_event_handler(id,e.keyCode);
366 };
367 const id = this.storeObject(handler);
368 element.addEventListener("keyup",handler);
369 return id;
370 }"#)
371 .invoke_and_return_bigint(&[element.into()]);
372 let function_handle = Arc::new(FunctionHandle(ExternRef {
373 value: function_ref,
374 }));
375 add_keyboard_event_handler(function_handle.clone(), Box::new(handler));
376 function_handle
377}
378
379pub fn element_remove_key_up_listener(element: &ExternRef, function_handle: &Arc<FunctionHandle>) {
380 let remove_key_up_listener = js!(r#"
381 function(element, f){
382 element.removeEventListener("keyup", f);
383 }"#);
384 remove_key_up_listener.invoke(&[element.into(), (&(function_handle.0)).into()]);
385 remove_keyboard_event_handler(function_handle);
386}