util.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //! Utilities specific to websys
  2. use std::{
  3. future::{IntoFuture, Ready},
  4. str::FromStr,
  5. };
  6. use dioxus_core::*;
  7. use serde::de::Error;
  8. use serde_json::Value;
  9. /// Get a closure that executes any JavaScript in the webpage.
  10. ///
  11. /// # Safety
  12. ///
  13. /// Please be very careful with this function. A script with too many dynamic
  14. /// parts is practically asking for a hacker to find an XSS vulnerability in
  15. /// it. **This applies especially to web targets, where the JavaScript context
  16. /// has access to most, if not all of your application data.**
  17. ///
  18. /// # Panics
  19. ///
  20. /// The closure will panic if the provided script is not valid JavaScript code
  21. /// or if it returns an uncaught error.
  22. pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) -> EvalResult {
  23. cx.use_hook(|| {
  24. |script: S| {
  25. let body = script.to_string();
  26. EvalResult {
  27. value: if let Ok(value) =
  28. js_sys::Function::new_no_args(&body).call0(&wasm_bindgen::JsValue::NULL)
  29. {
  30. if let Ok(stringified) = js_sys::JSON::stringify(&value) {
  31. if !stringified.is_undefined() && stringified.is_valid_utf16() {
  32. let string: String = stringified.into();
  33. Value::from_str(&string)
  34. } else {
  35. Err(serde_json::Error::custom("Failed to stringify result"))
  36. }
  37. } else {
  38. Err(serde_json::Error::custom("Failed to stringify result"))
  39. }
  40. } else {
  41. Err(serde_json::Error::custom("Failed to execute script"))
  42. },
  43. }
  44. }
  45. })
  46. }
  47. /// A wrapper around the result of a JavaScript evaluation.
  48. /// This implements IntoFuture to be compatible with the desktop renderer's EvalResult.
  49. pub struct EvalResult {
  50. value: Result<Value, serde_json::Error>,
  51. }
  52. impl EvalResult {
  53. /// Get the result of the Javascript execution.
  54. pub fn get(self) -> Result<Value, serde_json::Error> {
  55. self.value
  56. }
  57. }
  58. impl IntoFuture for EvalResult {
  59. type Output = Result<Value, serde_json::Error>;
  60. type IntoFuture = Ready<Result<Value, serde_json::Error>>;
  61. fn into_future(self) -> Self::IntoFuture {
  62. std::future::ready(self.value)
  63. }
  64. }