2

When executing a JavaScript in a WebEngine, how do I get the DOM using WebEngine.getDocument after the results of any deferred script execution? Here is the minimal code to demonstrate the question.

The following HTML when rendered in a standard browser does the following:

  1. Runs an inline script that dynamically adds an out-of-line script element
  2. The out-of-line script then adds a DOM element to the body

Here is the starting HTML:

<html>
  <head>
    <script>var y=document.createElement('script');
            y.src = 'http://example.com/js/bar.js';
            document.head.appendChild(y);
    </script>
  </head>
  <body>
  </body>
</html>

Here is what the out-of-line script bar.js contains:

var x=document.createElement('div'); x.id='bar'; document.body.appendChild(x);

After executing the above HTML in a standard browser, here is what the DOM looks like in a real browser but this is not what I'm getting with WebEngine (which I show later):

<html>
  <head>
    <script>var y=document.createElement('script'); y.src = 'http://example.com/js/bar.js'; document.head.appendChild(y);</script>
    <script src="http://example.com/js/bar.js"></script>
  </head>
  <body>
  <div id="bar"></div>
  </body>
</html>

I am trying to simulate the above using a headless JavaFX WebEngine using the following code (this is complete Java 8 code, minus the imports):

public class StackOverflowQuestion extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        final WebView browser = new WebView();
        final WebEngine webEngine = browser.getEngine();
        webEngine.setJavaScriptEnabled(true);
        webEngine.loadContent("<html><head></head><body></body></html>");

        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener() {
            @Override public void changed(ObservableValue o,Object oldVal, Object newVal) {
                if (newVal == State.SUCCEEDED) {
                    webEngine.executeScript("var y=document.createElement('script'); y.src = 'http://example.com/js/bar.js'; document.head.appendChild(y);");
                    Document document = webEngine.getDocument();
                    printDOM(document);
                } else {
                    System.out.println("Did not succeed");
                }
            }
        });
    }

    private void printDOM(Document document) {
        Transformer transformer;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
            transformer.setOutputProperty(OutputKeys.METHOD, "html");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
            transformer.transform(new DOMSource(document), new StreamResult(new OutputStreamWriter(System.out, "UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static public void main(String [] args) {
        try {
            Application.launch(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The above code outputs the following DOM structure. Note that the DOM contains the results of the executeScript call, but not the effects of what the out-of-line script produces. How do I get the DOM to include the dynamically added div element with id bar?

<HTML xmlns="http://www.w3.org/1999/xhtml">
    <HEAD>
        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <SCRIPT src="http://example.com/js/bar.js"></SCRIPT>
    </HEAD>
    <BODY></BODY>
</HTML>
Danger
  • 2,043
  • 2
  • 21
  • 24

0 Answers0