diff --git a/c/src/cef/v8_to_string.hpp b/c/src/cef/v8_to_string.hpp index 7ff4013..3dc26c5 100644 --- a/c/src/cef/v8_to_string.hpp +++ b/c/src/cef/v8_to_string.hpp @@ -1,6 +1,9 @@ #ifndef BW_CEF_V8_TO_STRING_HPP #define BW_CEF_V8_TO_STRING_HPP +#include +#include + class V8ToString { public: @@ -18,8 +21,13 @@ class V8ToString { return "null"; // If string - if ( val->IsString() ) - return val->GetStringValue(); + if ( val->IsString() ) { + std::string string = "\""; + // TODO: Escape the string value: + string += val->GetStringValue(); + string += "\""; + return string; + } // If boolean if ( val->IsBool() ) @@ -37,24 +45,44 @@ class V8ToString { if ( val->IsDouble() ) return intoString( val->GetDoubleValue() ); - // If object (unsupported) - if ( val->IsObject() ) - return "[object]"; - - // If array (unsupported) - if ( val->IsArray() ) - return "[array]"; + // If array + if ( val->IsArray() ) { + std::string string = "["; + for (int i = 0; i < val->GetArrayLength(); i++) { + if (i != 0) { + string += ","; + } + string += convert(val->GetValue(i)); + } + string += "]"; + return string; + } + + // If object + if ( val->IsObject() ) { + std::vector keys; + val->GetKeys(keys); + std::string string = "{"; + for (size_t i = 0; i < keys.size(); i++) { + std::string key = keys[i]; + if (i != 0) { + string += ","; + } + string += key + ":" + convert(val->GetValue(i)).ToString(); + } + string += "}"; + return string; + } - // If array (unsupported) if ( val->IsDate() ) - return "[date]"; + return "date"; // If exception (unsupported) if ( val->IsFunction() ) - return "[function]"; + return "function"; // If type is not accounted for, return this string: - return "[unknown type]"; + return "unknown type"; } protected: diff --git a/src/browser.rs b/src/browser.rs index e440908..01c79c0 100644 --- a/src/browser.rs +++ b/src/browser.rs @@ -132,6 +132,11 @@ impl BrowserWindowHandle { /// Executes the given javascript code and returns the output as a string. /// If you don't need the result, see `exec_js`. + /// + /// There may be some discrepancies in what JS values are being returned for + /// the same code in different browser engines. + /// For example, Edge WebView2 doesn't return `JsValue::Undefined`, it uses + /// `JsValue::Null` instead. pub async fn eval_js(&self, js: &str) -> Result { // let (tx, rx) = oneshot::channel(); diff --git a/src/core/browser_window/c.rs b/src/core/browser_window/c.rs index 18e1d54..054db77 100644 --- a/src/core/browser_window/c.rs +++ b/src/core/browser_window/c.rs @@ -44,7 +44,6 @@ impl BrowserWindowExt for BrowserWindowImpl { callback, data: callback_data, }); - let data_ptr = Box::into_raw(data); unsafe { @@ -246,7 +245,7 @@ unsafe extern "C" fn ffi_handler( let cmd_string: &str = cmd.into(); let mut args_vec: Vec = Vec::with_capacity(arg_count as usize); for i in 0..arg_count { - args_vec.push(JsValue::Other((*args.add(i as usize)).into())); + args_vec.push(JsValue::from_string((*args.add(i as usize)).into())); } (data.func)(handle, cmd_string, args_vec); @@ -262,9 +261,10 @@ unsafe fn ffi_eval_js_callback_result( let result_val: Result = if error.is_null() { let result_str = CStr::from_ptr(result) .to_string_lossy() - .to_owned() .to_string(); - Ok(JsValue::Other(result_str)) + + // Parse the string + Ok(JsValue::from_string(&result_str)) } else { Err(JsEvaluationError::new(error)) }; diff --git a/src/javascript.rs b/src/javascript.rs index 5356c92..ab6428a 100644 --- a/src/javascript.rs +++ b/src/javascript.rs @@ -1,10 +1,10 @@ -use std::{borrow::Cow, collections::HashMap, fmt}; +use std::{borrow::Cow, collections::HashMap, fmt, str::FromStr}; use json::JsonValue; pub use num_bigfloat::BigFloat; /// A JavaScript value. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum JsValue { Array(Vec), Boolean(bool), @@ -30,6 +30,37 @@ impl JsValue { } } + pub fn from_string(string: &str) -> Self { + if string.len() == 0 { + return Self::Other(String::new()); + } + + // If the symbol starts with a digit, interpret it as a (positive) number + if "0123456789".contains(|c| c == string.chars().nth(0).unwrap()) { println!("XXXXXXXXXXXXXXXX"); + return match BigFloat::from_str(string) { + Err(e) => Self::Other(format!("unable to parse number: {}", string)), + Ok(f) => Self::Number(f) + }; + } + if string == "null" { + return Self::Null; + } + if string == "undefined" { + return Self::Undefined; + } + if string == "true" { + return Self::Boolean(true); + } + if string == "false" { + return Self::Boolean(false); + } + if string.chars().nth(0) == Some('\"') { + return Self::String(string[1..(string.len()-1)].to_string()) + } + + Self::Other(string.to_string()) + } + fn _from_json(value: JsonValue) -> Self { match value { JsonValue::Null => Self::Null,