6 Replies Latest reply: Mar 27, 2013 1:53 PM by ttilt RSS

    Submiting HTML Forms with JavaFX Webview

    ttilt
      I've long been searching for a good web robot framework. And I also need a gui for my robot.

      So w/ the advent of JAVAFX Webengine it seemed my needs have been met finally. Specially because on the webview tutorial here , Alla Redko says: "+It supports user interaction such as navigating links *and submitting HTML forms*+".

      But after looking at the api it doesn't seem that webengine supports submiting forms, only loading pages w/ the load() method. I guess I could populate the form fields and submit them w/ executeScript() but that's just sloppy.

      Is there a way to actually submit forms w/ webengine? Are there plans to implement this feature, analogous to the load() method?

      Thanks,
      JC
        • 1. Re: Submiting HTML Forms with JavaFX Webview
          peterz
          Not yet. Do you need some method like post(String url, String formData) ?
          • 2. Re: Submiting HTML Forms with JavaFX Webview
            ttilt
            I need the ability to find certain form fields, populate them (or check/select them), then submit the form along w/ all other hidden inputs that came w/ the page.

            tks
            • 3. Re: Submiting HTML Forms with JavaFX Webview
              James_D
              I'm not a JavaScript expert, but JavaScript would be a way to do all of these things. The WebEngine defines an executeScript(...) method which you can use to execute JavaScript in the context of a loaded document.

              You could also, I think, do the first step ("find certain form fields") by accessing the document model with WebEngine.getDocument().
              • 4. Re: Submiting HTML Forms with JavaFX Webview
                ttilt
                Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.

                The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.

                Does anyone know if these things are planned for the future of Webview/Webengine?

                Tks
                • 5. Re: Submiting HTML Forms with JavaFX Webview
                  jsmith
                  Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.
                  The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.
                  Does anyone know if these things are planned for the future of Webview/Webengine?
                  You can already do this in Java today using the existing APIs if you so wished.
                  import javafx.application.Application;
                  import javafx.beans.property.*;
                  import javafx.beans.value.*;
                  import javafx.event.ActionEvent;
                  import javafx.event.EventHandler;
                  import javafx.scene.Scene;
                  import javafx.scene.control.*;
                  import javafx.scene.layout.*;
                  import javafx.scene.web.*;
                  import javafx.stage.Stage;
                  import org.w3c.dom.*;
                  import org.w3c.dom.html.*;
                   
                  public class WebViewFormPost extends Application {
                    public static void main(String[] args) { launch(args); }
                  
                    @Override public void start(Stage stage) {
                      final TextField fxUsername = new TextField();
                      final TextField fxPassword = new PasswordField();
                      
                      final BooleanProperty loginAttempted = new SimpleBooleanProperty(false);
                      
                      final WebView webView = new WebView();
                      final WebEngine engine = webView.getEngine();
                      engine.documentProperty().addListener(new ChangeListener<Document>() {
                        @Override public void changed(ObservableValue<? extends Document> ov, Document oldDoc, Document doc) {
                          if (doc != null && !loginAttempted.get()) {
                            if (doc.getElementsByTagName("form").getLength() > 0) {
                              HTMLFormElement form = (HTMLFormElement) doc.getElementsByTagName("form").item(0);
                              if ("/oam/server/sso/auth_cred_submit".equals(form.getAttribute("action"))) {
                                HTMLInputElement username = null;
                                HTMLInputElement password = null;
                                NodeList nodes = form.getElementsByTagName("input");
                                for (int i = 0; i < nodes.getLength(); i++) {
                                  HTMLInputElement input = (HTMLInputElement) nodes.item(i);
                                  switch (input.getName()) {
                                    case "ssousername":
                                      username = input;
                                      break;
                                    case "password":
                                      password = input;
                                      break;
                                  }
                                }
                                
                                if (username != null && password != null) {
                                  loginAttempted.set(true);
                                  username.setValue(fxUsername.getText());
                                  password.setValue(fxPassword.getText());
                                  form.submit();
                                  System.out.println("Submitted login for user: " + username);
                                }  
                              }  
                            }
                          }
                        }
                      });
                      engine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
                        @Override public void changed(ObservableValue<? extends Throwable> ov, Throwable oldException, Throwable exception) {
                          System.out.println("Load Exception: " + exception);
                        }
                      });
                  
                      GridPane inputGrid = new GridPane();
                      inputGrid.setHgap(10);
                      inputGrid.setVgap(10);
                      inputGrid.addRow(0, new Label("Username: "), fxUsername);
                      inputGrid.addRow(0, new Label("Password: "), fxPassword);
                      
                      Button fxLoginButton = new Button("Login to Oracle Forums");
                      fxLoginButton.setOnAction(new EventHandler<ActionEvent>() {
                        @Override public void handle(ActionEvent t) {
                          if (notEmpty(fxPassword.getText()) && notEmpty(fxPassword.getText())) {
                            loginAttempted.set(false);
                            engine.load("https://forums.oracle.com/forums/login!withRedirect.jspa");
                          }  
                        }
                      });
                      
                      final VBox layout = new VBox(10);
                      layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
                      layout.getChildren().addAll(
                        new Label("Enter your Oracle Web Account credentials"), 
                        inputGrid, 
                        fxLoginButton, 
                        webView
                      );
                      
                      stage.setScene(new Scene(layout));
                      stage.show();
                    }
                  
                    private boolean notEmpty(String s) {
                      return s != null && !"".equals(s);
                    }
                  }
                  Personally, I think using JavaScript via engine.executeScript calls in combination with jquery might be a less messy solution (as I don't like writing against the raw dom apis), but I understand that there are valid reasons why you might prefer to use a Java only solution.
                  https://gist.github.com/jewelsea/3077942 "Embeds jQuery in a document loaded into a WebView."
                  • 6. Re: Submiting HTML Forms with JavaFX Webview
                    ttilt
                    This is actually a pretty good solution.. I didn't know about this implementation in the org.w3c.dom.html package that already comes w/ Java. And by the way it's not part of the standard java7 javadoc. The javadoc is in a different url.

                    Just a remark: adding a listener to the doc change seems to be inefficient since as every new element is added to the DOM, it'll trigger a new call to this listener, and you'll only be returning from calls until the form element is completed. A better approach is the setOnSucceeded property of the WebEngine.getLoadWorker. That's what I'll try.

                    Thanks!
                    jsmith wrote:
                    Yea, as I mentioned in the first post, I could do all that w/ JS but it's just sloppy, since I'm using Java language, not JS.
                    The finding certain fields part is easy w/ the Document model and xpath, it's the populating the fields and submiting the form along w/ its hidden input fields that is the missing part.
                    Does anyone know if these things are planned for the future of Webview/Webengine?
                    You can already do this in Java today using the existing APIs if you so wished.
                    import javafx.application.Application;
                    import javafx.beans.property.*;
                    import javafx.beans.value.*;
                    import javafx.event.ActionEvent;
                    import javafx.event.EventHandler;
                    import javafx.scene.Scene;
                    import javafx.scene.control.*;
                    import javafx.scene.layout.*;
                    import javafx.scene.web.*;
                    import javafx.stage.Stage;
                    import org.w3c.dom.*;
                    import org.w3c.dom.html.*;
                    
                    public class WebViewFormPost extends Application {
                    public static void main(String[] args) { launch(args); }
                    
                    @Override public void start(Stage stage) {
                    final TextField fxUsername = new TextField();
                    final TextField fxPassword = new PasswordField();
                    
                    final BooleanProperty loginAttempted = new SimpleBooleanProperty(false);
                    
                    final WebView webView = new WebView();
                    final WebEngine engine = webView.getEngine();
                    engine.documentProperty().addListener(new ChangeListener<Document>() {
                    @Override public void changed(ObservableValue<? extends Document> ov, Document oldDoc, Document doc) {
                    if (doc != null && !loginAttempted.get()) {
                    if (doc.getElementsByTagName("form").getLength() > 0) {
                    HTMLFormElement form = (HTMLFormElement) doc.getElementsByTagName("form").item(0);
                    if ("/oam/server/sso/auth_cred_submit".equals(form.getAttribute("action"))) {
                    HTMLInputElement username = null;
                    HTMLInputElement password = null;
                    NodeList nodes = form.getElementsByTagName("input");
                    for (int i = 0; i < nodes.getLength(); i++) {
                    HTMLInputElement input = (HTMLInputElement) nodes.item(i);
                    switch (input.getName()) {
                    case "ssousername":
                    username = input;
                    break;
                    case "password":
                    password = input;
                    break;
                    }
                    }
                    
                    if (username != null && password != null) {
                    loginAttempted.set(true);
                    username.setValue(fxUsername.getText());
                    password.setValue(fxPassword.getText());
                    form.submit();
                    System.out.println("Submitted login for user: " + username);
                    }  
                    }  
                    }
                    }
                    }
                    });
                    engine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
                    @Override public void changed(ObservableValue<? extends Throwable> ov, Throwable oldException, Throwable exception) {
                    System.out.println("Load Exception: " + exception);
                    }
                    });
                    
                    GridPane inputGrid = new GridPane();
                    inputGrid.setHgap(10);
                    inputGrid.setVgap(10);
                    inputGrid.addRow(0, new Label("Username: "), fxUsername);
                    inputGrid.addRow(0, new Label("Password: "), fxPassword);
                    
                    Button fxLoginButton = new Button("Login to Oracle Forums");
                    fxLoginButton.setOnAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent t) {
                    if (notEmpty(fxPassword.getText()) && notEmpty(fxPassword.getText())) {
                    loginAttempted.set(false);
                    engine.load("https://forums.oracle.com/forums/login!withRedirect.jspa");
                    }  
                    }
                    });
                    
                    final VBox layout = new VBox(10);
                    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
                    layout.getChildren().addAll(
                    new Label("Enter your Oracle Web Account credentials"), 
                    inputGrid, 
                    fxLoginButton, 
                    webView
                    );
                    
                    stage.setScene(new Scene(layout));
                    stage.show();
                    }
                    
                    private boolean notEmpty(String s) {
                    return s != null && !"".equals(s);
                    }
                    }
                    Personally, I think using JavaScript via engine.executeScript calls in combination with jquery might be a less messy solution (as I don't like writing against the raw dom apis), but I understand that there are valid reasons why you might prefer to use a Java only solution.
                    https://gist.github.com/jewelsea/3077942 "Embeds jQuery in a document loaded into a WebView."
                    Edited by: ttilt on 27/03/2013 11:47