My company is looking to switch up our embedded browser to JavaFx. However, our current browser currently has functionality that listens to a javascript function, and calls back to java whenever it is called. It looks like this:
embeddedBrowser.registerFunction("ajavascriptFunction", new BrowserFunction() {
public JSValue invoke(JSValue... args) {
//Do callback work
}
});
This requires no modification of the html side (a requirement) and in fact only requires knowledge of the javascript function name (I might be able to research more information, but this is highly preferred).
Is there anyway to use JavaFx in the same way?
I think this does what you need. I borrowed an idea from this question to figure out the javascript:
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JavaScriptFunctionListener extends Application {
@Override
public void start(Stage primaryStage) {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
addFunctionHandlerToDocument(engine);
}
});
// Just a demo: in real life can load external HTML resource:
engine.loadContent(
"<html><head><script>"
+ "var count = 0 ;"
+ "function someFunction(x) {"
+ " count ++ ;"
+ " document.getElementById(x).innerHTML = 'Count: '+count ;"
+ "}"
+ "</script></head>"
+ "<body>"
+ " <input type=\"button\" value=\"Click Me\" onclick=\"someFunction('display');\"/>"
+ " <div id='display'></div>"
+ "</body>"
+ "</html>"
);
Button registerButton = new Button("Register handler for 'someFunction'");
registerButton.setOnAction(event -> {
registerFunction("someFunction", engine);
// registering the same function twice will break everything
// so don't allow this to happen again:
registerButton.setDisable(true);
});
HBox controls = new HBox(5, registerButton);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
BorderPane root = new BorderPane(webView, null, null, controls, null);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private void registerFunction(String functionName, WebEngine engine) {
engine.executeScript(
"var fun = " + functionName + " ;"
+ functionName + " = function() {"
+ " app.functionCalled('" + functionName + "');"
+ " fun.apply(this, arguments)"
+ "}"
);
}
private void addFunctionHandlerToDocument(WebEngine engine) {
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", this);
}
public void functionCalled(String name) {
System.out.println(name + " was called");
}
public static void main(String[] args) {
launch(args);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With