5

JavaFX shows some odd behaviour when loading a page that has an identical url to a page that has been loaded before. The code below demonstrates this issue:

After class initalization a page is loaded, then a highlight is applied to an arbitrary html element using a custom style class. This highlight is rendered correctly.

Finally, through user input event, the WebView is told to load a new page (with the same URI). Instead of showing the page as-is, the highlight is shown as well.

WebView webView = new WebView();
static String URI = "http://www.example.com";

public void loadPage() {
    // Step 1: load page
    webView.getEngine().load(URI);

    // Step 2: Change style attribute in page
    (Element) element = xpath.evaluate("//div[@id='mydiv']", webView.getEngine().getDocument(), XPathConstants.NODE);
    element.setAttribute("class", "mystyle");
}

handle() {
    // Step 3: load page again
    webView.getEngine().load(URI);
}

I have experimented with forcing the page to reload with WebView.getEngine().reload(), disabling cache, waiting for workers to complete, etc.

The only option I currently see is to create a new instance of the WebView, but as this is pretty CPU heavy, I prefer to reuse the object rather than creating it new every time I want to revert to the original page.

Stern
  • 130
  • 1
  • 8
  • What do you mean by " rebuilding the entire WebView"? Calling the `webView.getEngine().load("your url");` again should suffice. It is like a refreshing of a webpage. No need to recreate a webview instance. – Uluk Biy Aug 19 '13 at 16:16
  • I've reworded my text, but yes, as it stands the only working solution I have is to create a new instance of the webview every time I want to reload a page for which I have played with the DOM Document before. It appears that the DOM Document, gets cached internally in the WebView engine. – Stern Aug 20 '13 at 06:51

1 Answers1

2

Here is a SSCCE that demonstrates the reloading of the HTML content. It is bit different from your approach but the story is the same, though didn't try loading an external URL like yours. You are right about caching of webEngine since the webEngine.reload() does not load the original content.

public class WebViewReload extends Application {

    private String content = "<html>"
            + "    <head>"
            + "         <style type=\"text/css\">"
            + "            .mystyle {"
            + "                padding: 20px;"
            + "                background-color: red;"
            + "                font-size: 30px;"
            + "            }"
            + "        </style>"
            + "    </head>"
            + "    <body>"
            + "        <div id=\"mydiv\">initial content</div>"
            + "    </body>"
            + "</html>";

    @Override
    public void start(final Stage stage) throws Exception {
        final WebView webView = new WebView();
        webView.getEngine().loadContent(content);
        // It is same as loading an external html source, like this
        // webView.getEngine().load(getClass().getResource("my.html").toExternalForm());

        Button btn1 = new Button("Apply style");
        btn1.setPrefWidth(200);
        btn1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Element element = webView.getEngine().getDocument().getElementById("mydiv");
                element.setAttribute("class", "mystyle");
                element.setTextContent("new content");
            }
        });

        Button btn2 = new Button("Reload content");
        btn2.setPrefWidth(200);
        btn2.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                webView.getEngine().loadContent(content);
                // following does not reload at all
                // webView.getEngine().reload();
            }
        });

        VBox vbox = new VBox(10);
        vbox.setPadding(new Insets(20));
        vbox.setStyle("-fx-background-color: gray");
        vbox.getChildren().addAll(webView, btn1, btn2);

        Scene scene = new Scene(vbox);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Uluk Biy
  • 48,655
  • 13
  • 146
  • 153
  • Thank you for confirming the issue Uluk. – Stern Aug 21 '13 at 12:14
  • @Stern. As I said before, `webView.getEngine().loadContent(content);` (in "Reload content" button above) loads the original content however. Are wee agreed on this? – Uluk Biy Aug 21 '13 at 12:29
  • Correct, and also makes sense as loadContent requires the DOM Document to be rebuild. I'm still looking into this issue. I found that updating the DOM Document after a user input event in the WebView actually works as intended. It appears that such an event triggers an internal review of the document. – Stern Aug 22 '13 at 11:32