I'm creating a page that will be opened either in the WebView from Java, or manually in external browser. If page is loaded from Java - I need it to perform specific callbacks, cuz Java is used as kind of a backend, but if page is loaded manually it should load different data from its resources. So i'm trying to register a JS "JavaInit" object that could be called on document load. HTML looks sort of like this:
<html>
<head>
<script type='text/javascript' src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript">
DefaultInit = {
init: function(x) {
return "Default init: " + x;
}
};
$(function() {
var text;
if (window["JavaInit"] && JavaInit.init)
text = JavaInit.init("passed text");
else
text = DefaultInit.init("passed text");
$("#title").html(text);
});
</script>
</head>
<body>
<h1 id="title"></h1>
</body>
</html>
I've read about problems setting a JS member before page onload event here: javaFX webview window.onload is fired before loadworker succeeds, so my Java code looks like this:
public class Test extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
WebView web = new WebView();
Scene scene = new Scene(web, 400, 300);
primaryStage.setScene(scene);
primaryStage.show();
initWeb(web);
}
private static void initWeb(WebView web) {
WebEngine eng = web.getEngine();
((JSObject)eng.executeScript("window")).setMember("JavaInit", new JavaInit());
URL url = Test.class.getResource("/test.html");
eng.load(url.toString());
}
public static class JavaInit {
public String init(Object o) {
return "Java init: " + o;
}
}
}
And it works exactly as required, but only once, before anyone calls "Reload page". After reload engine seems to recreate the "window" object and all registered members disappear.
It is possible to place #setMember inside a "state property" listener:
private static void initWeb(WebView web) {
WebEngine eng = web.getEngine();
eng.getLoadWorker().stateProperty().addListener((val, oldState, newState) -> {
if (newState == State.SUCCEEDED)
((JSObject)eng.executeScript("window")).setMember("JavaInit", new JavaInit());
});
URL url = Test.class.getResource("/test.html");
eng.load(url.toString());
}
But then it's called only after window.onload were fired, and default init is called all the time. Which can be fixed by calling init code with minimal delay:
$(function() {
setTimeout(function() {
var text;
if (window["JavaInit"] && JavaInit.init)
text = JavaInit.init("passed text");
else
text = DefaultInit.init("passed text");
$("#title").html(text);
});
});
Then control got handled from JS back to Java (if present), and then gets back to registered function, and programm works fine everytime.
But it seems kinda wrong, to create init delay in hope that Java will successfully register all the members. So anybody knows any "more proper" way to achieve this kind of functionality? And is it possible that in the production it could take more time, and JS could call delayed function before members are registered? Or is there any guarantee WebEngine will handle Java events and JS execution continuously?
Thanks!