fltk-rs / fltk-webview

webview functionality for embedded fltk windows
MIT License
47 stars 7 forks source link

Javascript bind->return example #7

Open ajnewlands opened 3 years ago

ajnewlands commented 3 years ago

Hello,

It would be very helpful to have a 'hello world' style example of binding a native function into the JavaScript environment and returning a value. I've been able to do the former, but haven't succeeded in actually resolving the returned promise on the JavaScript side.

On the Rust side I have:

    let wvc = wv.clone();
    wv.bind("RustMethod", move |seq, content| {
        println!("{}, {}", seq, content);
        wvc.r#return(seq, 0, "{}");
    });

On the JavaScript side I have tried a few variations on

document.addEventListener("DOMContentLoaded", function() {
    RustMethod("foo").then(
        (response) => {
            console.log("Callback " + response);
        },
        (reject) => {
            console.log("Rejection " + reject);
        }
    );
});

On the Rust side, the method is clearly invoked as evidenced by the println!() macro generating output. However, the promise returned by RustMethod seems to never resolve, suggesting that something is awry with the parameters passed to the return method.

Any pointer towards getting this to work would be much appreciated :-)

MoAlyousef commented 3 years ago

Hello

I'm not sure I understood the question. The seq parameter is used to match methods using webview's internal RPC engine. The req/content parameter is the arguments passed to the js function, represented as JSON. A small example:

extern crate fltk;
extern crate tinyjson; // We use the tinyjson crate to parse the content parameter

use fltk::{app, prelude::*, window};
use tinyjson::JsonValue;

const HTML: &str = r#"
data:text/html,
<!doctype html>
<html>
<body>hello</body>
<script>
    window.onload = function() {
        add(1, 2).then(function(res) {
            document.body.innerText = `added, ${res}`;
          });
    };
</script>
</html>"#;

fn main() {
    let app = app::App::default();
    let mut win = window::Window::default()
        .with_size(800, 600)
        .with_label("Webview");
    let mut wv_win = window::Window::default()
        .with_size(790, 590)
        .center_of_parent();
    win.end();
    win.make_resizable(true);
    win.show();

    let mut wv = fltk_webview::Webview::create(true, &mut wv_win);
    wv.navigate(HTML);

    let wvc = wv.clone();
    wv.bind("add", move |seq, content| {
        println!("{}, {}", seq, content);
        let parsed: JsonValue = content.parse().unwrap();
        let val1: &f64 = parsed[0].get().unwrap();
        let val2: &f64 = parsed[1].get().unwrap();
        let ret = val1 + val2;
        wvc.r#return(seq, 0, &ret.to_string());
    });

    app.run().unwrap();
}

If you mean you want to get the value out of the closure, you can do that by passing a smart pointer (usually a Rc<RefCell<T>>, borrow_mut() in the closure, this will give you the value even outside the closure.

    let ret = Rc::from(RefCell::from(0.0));
    let ret_c = ret.clone();
    let wvc = wv.clone();
    wv.bind("add", move |seq, content| {
        println!("{}, {}", seq, content);
        let parsed: JsonValue = content.parse().unwrap();
        let val1: &f64 = parsed[0].get().unwrap();
        let val2: &f64 = parsed[1].get().unwrap();
        *ret_c.borrow_mut() = val1 + val2;
        wvc.r#return(seq, 0, &ret_c.borrow().to_string());
    });
ajnewlands commented 3 years ago

Hi Mohammed, thank you for getting back to me.

The first case, with the "add" method is exactly what I am talking about. I added the source code above to a brand new project and it exhibits the same behavior as I saw with my own code, i.e. (1) stdout reports the sequence number and argument array (2) The promise doesn't seem to resolve on the javascript side (the body of the document continues to show 'Hello' rather than 'added, 3' as I would expect).

I assume it does work on your system, so perhaps it is platform specific (I tried on a pair of Windows 10 machines with the webview 2 runtime). I'll set up a Linux instance with X11, try it there and report back.

Thanks! Andrew

ajnewlands commented 3 years ago

I went and tried the same code on Linux and observed that it does indeed work, so it appears that the webview::return method fails on Windows, only, at least on the pair of machines I tried.

MoAlyousef commented 3 years ago

Yeah I finally tried on Windows also, and I see what you mention. I think it's this issue here: https://github.com/webview/webview/issues/498