diff --git a/examples/README.md b/examples/README.md index 69d15cf86..e1897db8b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -42,6 +42,7 @@ These examples are not necessarily meant to be run, but rather serve as a refere | [Complete rsx reference](./rsx_usage.rs) | A complete reference for all rsx! usage | ✅ | | [Event Listeners](./listener.rs) | Attach closures to events on elements | ✅ | | [Inline Props](./inlineprops.rs) | Using the `#[inline_props]` macro | ✅ | +| [Eval](./eval.rs) | Evaluate dynamic JavaScript code | ✅ | ## Show me some examples! diff --git a/examples/eval.rs b/examples/eval.rs new file mode 100644 index 000000000..c0801b507 --- /dev/null +++ b/examples/eval.rs @@ -0,0 +1,25 @@ +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let script = use_state(&cx, String::new); + let eval = use_eval(&cx); + + cx.render(rsx! { + div { + input { + placeholder: "Enter an expression", + value: "{script}", + oninput: move |e| script.set(e.value.clone()), + } + button { + onclick: move |_| eval(script), + + "Execute" + } + } + }) +} diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 93162842b..4ad2ff3a7 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -119,6 +119,11 @@ impl DesktopContext { pub fn devtool(&self) { let _ = self.proxy.send_event(DevTool); } + + /// run (evaluate) a script in the WebView context + pub fn eval(&self, script: impl std::string::ToString) { + let _ = self.proxy.send_event(Eval(script.to_string())); + } } #[derive(Debug)] @@ -144,6 +149,8 @@ pub enum UserWindowEvent { SetDecorations(bool), DevTool, + + Eval(String), } pub(super) fn handler( @@ -185,5 +192,16 @@ pub(super) fn handler( SetDecorations(state) => window.set_decorations(state), DevTool => webview.devtool(), + + Eval(code) => webview + .evaluate_script(code.as_str()) + .expect("eval shouldn't panic"), } } + +/// Get a closure that executes any JavaScript in the WebView context. +pub fn use_eval(cx: &ScopeState) -> &dyn Fn(S) { + let desktop = use_window(&cx).clone(); + + cx.use_hook(|_| move |script| desktop.eval(script)) +} diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 4b2615d54..596956c53 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -11,7 +11,7 @@ mod events; mod protocol; use desktop_context::UserWindowEvent; -pub use desktop_context::{use_window, DesktopContext}; +pub use desktop_context::{use_eval, use_window, DesktopContext}; pub use wry; pub use wry::application as tao; diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index c82dc4975..da3955d1b 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -57,6 +57,7 @@ use std::rc::Rc; pub use crate::cfg::WebConfig; +pub use crate::util::use_eval; use dioxus::SchedulerMsg; use dioxus::VirtualDom; pub use dioxus_core as dioxus; @@ -68,6 +69,7 @@ mod cfg; mod dom; mod rehydrate; mod ric_raf; +mod util; /// Launch the VirtualDOM given a root component and a configuration. /// diff --git a/packages/web/src/util.rs b/packages/web/src/util.rs index 638cf3dc2..3e7232035 100644 --- a/packages/web/src/util.rs +++ b/packages/web/src/util.rs @@ -1 +1,26 @@ //! Utilities specific to websys + +use dioxus_core::*; + +/// Get a closure that executes any JavaScript in the webpage. +/// +/// # Safety +/// +/// Please be very careful with this function. A script with too many dynamic +/// parts is practically asking for a hacker to find an XSS vulnerability in +/// it. **This applies especially to web targets, where the JavaScript context +/// has access to most, if not all of your application data.** +/// +/// # Panics +/// +/// The closure will panic if the provided script is not valid JavaScript code +/// or if it returns an uncaught error. +pub fn use_eval(cx: &ScopeState) -> &dyn Fn(S) { + cx.use_hook(|_| { + |script: S| { + js_sys::Function::new_no_args(&script.to_string()) + .call0(&wasm_bindgen::JsValue::NULL) + .expect("failed to eval script"); + } + }) +} diff --git a/src/lib.rs b/src/lib.rs index cebffcf17..748772aa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,16 @@ pub use dioxus_core as core; -#[cfg(feature = "hooks")] -pub use dioxus_hooks as hooks; +pub mod hooks { + #[cfg(feature = "hooks")] + pub use dioxus_hooks::*; + + #[cfg(all(target = "wasm", feature = "web"))] + pub use dioxus_web::use_eval; + + #[cfg(all(not(target = "wasm"), feature = "desktop"))] + pub use dioxus_desktop::use_eval; +} #[cfg(feature = "router")] pub use dioxus_router as router; @@ -32,10 +40,10 @@ pub mod events { } pub mod prelude { + pub use crate::hooks::*; pub use dioxus_core::prelude::*; pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props}; pub use dioxus_elements::{GlobalAttributes, SvgAttributes}; - pub use dioxus_hooks::*; pub use dioxus_html as dioxus_elements; #[cfg(feature = "router")]