I have a requirement to record events performed on a web page.
Eg. Filling registration form.
Recorder should capture the keyword entries and clicks performed on the page and play back when requested. At time same time recorder should also capture the actual element that generates the event. Say when i key in the firstName in
<input type="text" id="f_name"/>
recorder should be able to capture the id 'f_name'
I was wondering if I could use JavaFX for that!?. JavaFX is allowing me to load a page and I could detect various operations performed on the page by registering the appropriate event listeners. But it is not giving me any useful information about which element in the page has created that event.
package test1;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JSTEst2 extends Application{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
//if the page is loaded
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", this);
//System.out.println(engine.executeScript("document.querySelector('body').innerHTML"));
//engine.executeScript("document.querySelector('body').addEventListener('click', function(event) { alert(event.target.id); app.getCallBack(event.target.id);}, false);");
engine.executeScript("document.addEventListener('click', function(event) { alert(event.target.id); app.getCallBack(event.target.id);}, false);");
}
});
/*engine.loadContent(
"<html><body>"
+ " <ul class=\"ct\">"
+ "<li id=\"first\">first</li>"
+ "<li id=\"second\">second</li>"
+ " <li id=\"third\">third</li>"
+ "</ul>"
+ "<input type=\"button\" value=\"Add <li>\" />"
+ "</body>"
+ "</html>"
);*/
engine.load("<my_url>");
//String javascript = "document.querySelector('body').addEventListener('click', function(event) { if (event.target.tagName.toLowerCase() === 'li') { console.log(event.target.id); alert(event.target.id); }});";
engine.setOnAlert(event -> showAlert(event.getData()));
engine.setConfirmHandler(message -> showConfirm(message));
//engine.executeScript(javascript);
VBox root = new VBox();
root.getChildren().add(webView);
root.setStyle("-fx-padding: 10;" +
"-fx-border-style: solid inside;" +
"-fx-border-width: 2;" +
"-fx-border-insets: 5;" +
"-fx-border-radius: 5;" +
"-fx-border-color: blue;");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showAlert(String message) {
Dialog<Void> alert = new Dialog<>();
alert.getDialogPane().setContentText(message);
alert.getDialogPane().getButtonTypes().add(ButtonType.OK);
alert.showAndWait();
}
private boolean showConfirm(String message) {
Dialog<ButtonType> confirm = new Dialog<>();
confirm.getDialogPane().setContentText(message);
confirm.getDialogPane().getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
boolean result = confirm.showAndWait().filter(ButtonType.YES::equals).isPresent();
// for debugging:
System.out.println(result);
return result ;
}
private void getCallBack(String data) {
System.out.println("---->" + data);
}
}
When i clicked on 'firstname' input field,

the sys out in the listener printed something like this,
WebView@90e64cf[styleClass=web-view]
javafx.scene.Scene@52fca713
which I can hardly interpret.
Is JavaFX he right approach is this case? If Yes, how do i get the required information using JavaFX?
##################UPDATE##################
I have updated the code to use executeScript() method. Now it shows the target element id in alert box, but i need to communicate it back to my java application. The logic I have in the code is not working. Any thoughts!!?
To get informations about events from website, you can call methods from Javascript to your WebEngine:
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
Engine.executeScript("document.cookie");
To have a 2-way communication between Javascript and Java. You have to set member for window and create method to call it in Javascript. Full working script:
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JSTEst2 extends Application{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
//if the page is loaded
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", this);
engine.executeScript("document.addEventListener('click', function(event) { alert(event.target.id); app.getCallBack(event.target.id);}, false);");
}
});
engine.load("<my_url>");
engine.setOnAlert(event -> showAlert(event.getData()));
engine.setConfirmHandler(message -> showConfirm(message));
VBox root = new VBox();
root.getChildren().add(webView);
root.setStyle("-fx-padding: 10;" +
"-fx-border-style: solid inside;" +
"-fx-border-width: 2;" +
"-fx-border-insets: 5;" +
"-fx-border-radius: 5;" +
"-fx-border-color: blue;");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showAlert(String message) {
Dialog<Void> alert = new Dialog<>();
alert.getDialogPane().setContentText(message);
alert.getDialogPane().getButtonTypes().add(ButtonType.OK);
alert.showAndWait();
}
private boolean showConfirm(String message) {
Dialog<ButtonType> confirm = new Dialog<>();
confirm.getDialogPane().setContentText(message);
confirm.getDialogPane().getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
boolean result = confirm.showAndWait().filter(ButtonType.YES::equals).isPresent();
// for debugging:
System.out.println(result);
return result ;
}
public void getCallBack(String data) {
System.out.println("---->" + data);
}
}
}
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