1
use serde::{Deserialize, Serialize};
2
use wasm_bindgen::prelude::*;
3

            
4
pub mod autocomplete;
5
pub mod data_attrs;
6
pub mod htmx;
7
pub mod transaction;
8
pub mod types;
9

            
10
pub use transaction::{add_split_tag, get_split_count, remove_split_tag};
11
pub use types::*;
12

            
13
#[derive(Serialize, Deserialize)]
14
pub struct WasmStatus {
15
    loaded: bool,
16
    version: String,
17
    message: String,
18
}
19

            
20
#[wasm_bindgen]
21
#[must_use]
22
pub fn get_wasm_status() -> JsValue {
23
    let status = WasmStatus {
24
        loaded: true,
25
        version: env!("CARGO_PKG_VERSION").to_string(),
26
        message: "WASM module loaded successfully".to_string(),
27
    };
28
    serde_wasm_bindgen::to_value(&status).unwrap()
29
}
30

            
31
#[cfg(feature = "auto-init")]
32
#[wasm_bindgen(start)]
33
pub fn main() {
34
    console_error_panic_hook::set_once();
35
    register_global_functions();
36
    htmx::setup_htmx_validation();
37
    setup_htmx_listener();
38

            
39
    let Some(document) = web_sys::window().and_then(|w| w.document()) else {
40
        return;
41
    };
42

            
43
    if document.ready_state() == "loading" {
44
        let callback = wasm_bindgen::closure::Closure::wrap(Box::new(|| {
45
            autocomplete::init_all();
46
            init_transaction_form();
47
        }) as Box<dyn Fn()>);
48

            
49
        let _ = document.add_event_listener_with_callback(
50
            "DOMContentLoaded",
51
            callback.as_ref().unchecked_ref(),
52
        );
53
        callback.forget();
54
    } else {
55
        autocomplete::init_all();
56
        init_transaction_form();
57
    }
58
}
59

            
60
#[cfg(feature = "auto-init")]
61
fn register_global_functions() {
62
    use wasm_bindgen::JsCast;
63

            
64
    let Some(window) = web_sys::window() else {
65
        return;
66
    };
67

            
68
    let get_split_count = Closure::wrap(Box::new(get_split_count) as Box<dyn Fn() -> u32>);
69
    let _ = js_sys::Reflect::set(
70
        &window,
71
        &"getSplitCount".into(),
72
        get_split_count.as_ref().unchecked_ref(),
73
    );
74
    get_split_count.forget();
75

            
76
    let add_split_tag = Closure::wrap(Box::new(|el: web_sys::HtmlElement| {
77
        add_split_tag(&el);
78
    }) as Box<dyn Fn(web_sys::HtmlElement)>);
79
    let _ = js_sys::Reflect::set(
80
        &window,
81
        &"addSplitTag".into(),
82
        add_split_tag.as_ref().unchecked_ref(),
83
    );
84
    add_split_tag.forget();
85

            
86
    let remove_split_tag = Closure::wrap(Box::new(|el: web_sys::HtmlElement| {
87
        remove_split_tag(&el);
88
    }) as Box<dyn Fn(web_sys::HtmlElement)>);
89
    let _ = js_sys::Reflect::set(
90
        &window,
91
        &"removeSplitTag".into(),
92
        remove_split_tag.as_ref().unchecked_ref(),
93
    );
94
    remove_split_tag.forget();
95
}
96

            
97
#[cfg(feature = "auto-init")]
98
fn init_transaction_form() {
99
    let Some(document) = web_sys::window().and_then(|w| w.document()) else {
100
        return;
101
    };
102

            
103
    let is_transaction_page = document
104
        .query_selector("#splits-container")
105
        .ok()
106
        .flatten()
107
        .is_some();
108

            
109
    if is_transaction_page {
110
        transaction::setup_field_validation();
111
        transaction::setup_form_submit_handler();
112
        transaction::setup_split_handlers();
113
        transaction::initialize_transaction_form();
114
    }
115
}
116

            
117
#[cfg(feature = "auto-init")]
118
fn setup_htmx_listener() {
119
    let Some(document) = web_sys::window().and_then(|w| w.document()) else {
120
        return;
121
    };
122

            
123
    let callback = Closure::wrap(Box::new(|_: web_sys::Event| {
124
        autocomplete::init_all();
125
    }) as Box<dyn FnMut(_)>);
126

            
127
    let _ = document
128
        .add_event_listener_with_callback("htmx:afterSwap", callback.as_ref().unchecked_ref());
129
    callback.forget();
130
}