Răsfoiți Sursa

Merge pull request #318 from overlisted/eval-stuff

Eval stuff
Jon Kelley 3 ani în urmă
părinte
comite
56ea9e42fa

+ 1 - 0
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!

+ 25 - 0
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"
+            }
+        }
+    })
+}

+ 18 - 0
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<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
+    let desktop = use_window(&cx).clone();
+
+    cx.use_hook(|_| move |script| desktop.eval(script))
+}

+ 1 - 1
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;
 

+ 2 - 0
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.
 ///

+ 25 - 0
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<S: std::string::ToString>(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");
+        }
+    })
+}

+ 11 - 3
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")]