simi 0.2.1

A framework for building wasm front-end web application in Rust
//! Things from the browser

pub use web_sys::{Element, Node};

/// Get document object
pub fn document() -> web_sys::Document {
    web_sys::window()
        .expect("Must have a window")
        .document()
        .expect("Must have a document")
}

/// Html element events, mostly for use by the macros with require users to depend on web-sys.
/// (Users still need to add web-sys to their [dependencies] if they use them outside of the macros).
pub mod element_events {
    pub use web_sys::{
        Event, FocusEvent, InputEvent, KeyboardEvent, MouseEvent, UiEvent, WheelEvent,
    };
}

/// A console that use str instead of JsValue
pub mod console {
    use wasm_bindgen::JsValue;
    /// Log
    pub fn log(s: &str) {
        web_sys::console::log_1(&JsValue::from(s));
    }
}

/// Help js send messages back to your simi app
pub mod callback {
    use crate::app::{Application, WeakMain};
    #[cfg(feature = "js_callback_with_serde_arg")]
    use serde::Deserialize;
    use wasm_bindgen::closure::Closure;

    /// Create a callback that requires no argument
    pub fn no_arg<A, H>(main: WeakMain<A>, handler: H) -> Closure<Fn()>
    where
        A: Application + 'static,
        H: Fn() -> A::Message + 'static,
    {
        let handler = move || main.send_message(handler());
        Closure::wrap(Box::new(handler) as Box<Fn()>)
    }

    /// Create a `wasm_bindgen::closure::Closure` for a handler that requires an argument.
    /// The argument received from JavaScript is intepreted as a wasm_bindgen::JsValue. Then will
    /// be deserialize into the Rust type T using serde
    #[cfg(feature = "js_callback_with_serde_arg")]
    pub fn with_serde_arg<A, T, H>(
        main: WeakMain<A>,
        handler: H,
    ) -> Closure<Fn(wasm_bindgen::JsValue)>
    where
        A: Application + 'static,
        H: Fn(T) -> A::Message + 'static,
        for<'a> T: Deserialize<'a> + 'static,
    {
        let handler = move |value: wasm_bindgen::JsValue| {
            let value: Result<T, serde_json::Error> = value.into_serde();
            match value {
                Ok(value) => main.send_message(handler(value)),
                Err(_) => crate::interop::console::log("Deserialize error"),
            }
        };
        Closure::wrap(Box::new(handler) as Box<Fn(wasm_bindgen::JsValue)>)
    }
}

/// Help js callback a method of the user app's context
pub mod context_callback {
    /// Create a callback that executes a method (no arguments) of `Application::Context`
    #[macro_export]
    macro_rules! context_callback_no_arg {
        ($weak_main:expr, $context_method_name:ident) => {{
            let main = $weak_main.get_inner();
            let handler = move || match main.upgrade() {
                None => $crate::interop::console::log("Fail to upgrade weak main to rc main"),
                Some(mut main) => match main.try_borrow_mut() {
                    Err(e) => $crate::interop::console::log(&e.to_string()),
                    Ok(mut main) => main.get_app_context_mut().$context_method_name(),
                },
            };
            Closure::wrap(Box::new(handler) as Box<Fn()>)
        }};
    }

    /// Create a callback that executes a method (requires arguments) of `Application::Context`
    #[macro_export]
    macro_rules! context_callback_args {
            ($weak_main:expr, $context_method_name:ident ($($arg_name:ident: $arg_type:ident),+)) => {{
                    let main = $weak_main.get_inner();
                    let handler = move |$($arg_name: $arg_type),+| match main.upgrade() {
                            None => $crate::interop::console::log(
                                    "Fail to upgrade weak main to rc main",
                            ),
                            Some(mut main) => match main.try_borrow_mut() {
                                    Err(e) => $crate::interop::console::log(&e.to_string()),
                                    Ok(mut main) => {
                                            main.get_app_context_mut().$context_method_name($($arg_name),+)
                                    }
                            },
                    };
                    Closure::wrap(Box::new(handler) as Box<Fn($($arg_type),+)>)
            }};
    }

    /// Create a callback that executes a method (require a single argument that is deserialized
    /// from a JsValue that contains json string) of `Application::Context`
    #[macro_export]
    macro_rules! context_callback_with_serde_arg {
        ($weak_main:expr, $context_method_name:ident, $Type:ident) => {{
            let main = $weak_main.get_inner();
            let handler = move |value: wasm_bindgen::JsValue| match main.upgrade() {
                None => $crate::interop::console::log("Fail to upgrade weak main to rc main"),
                Some(mut main) => match main.try_borrow_mut() {
                    Err(e) => $crate::interop::console::log(&e.to_string()),
                    Ok(mut main) => {
                        let value: Result<$Type, $crate::serde_json::Error> = value.into_serde();
                        match value {
                            Ok(value) => main.get_app_context_mut().$context_method_name(value),
                            Err(_) => $crate::interop::console::log("Deserialize error"),
                        }
                    }
                },
            };
            Closure::wrap(Box::new(handler) as Box<Fn(wasm_bindgen::JsValue)>)
        }};
    }
}