Html/JavaScript Debugging in Javafx Webview

Html/Javascript debugging in JavaFX WebView

Here is some Java code to make use of Firebug Lite in a JavaFX WebView without modifying the html of the target page.

webView.getEngine().executeScript("if (!document.getElementById('FirebugLite')){E = document['createElement' + 'NS'] && document.documentElement.namespaceURI;E = E ? document['createElement' + 'NS'](E, 'script') : document['createElement']('script');E['setAttribute']('id', 'FirebugLite');E['setAttribute']('src', 'https://getfirebug.com/' + 'firebug-lite.js' + '#startOpened');E['setAttribute']('FirebugLite', '4');(document['getElementsByTagName']('head')[0] || document['getElementsByTagName']('body')[0]).appendChild(E);E = new Image;E['setAttribute']('src', 'https://getfirebug.com/' + '#startOpened');}"); 

You can trigger the code using a JavaFX Button or any other mechanism you wish.

JAVAFX / WebView / WebEngine FireBugLite or Some other debugger?

I was able to fix the problem. It seems like the current stable version of FirebugLite works well for traditional browsers but something is different that makes it fail for an application viewed by the JAVAFX WebView.

I was able to add Firebug to my application by using an uncompressed version of FirebugLite

<script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>

The solution came from: Testing IE6 with Firebug Lite

JavaFx WebView callback from Javascript failing after Garbage Collection

I solved the problem by creating an instance variable bridge in Java that holds the JavaScriptBridge instance sent to Javascript via setMember(). This way, Gargbage Collection of the instance is prevented.

Relevant code snippet:

public class JavaScriptBridge {
public void callback(String data) {
System.out.println("callback retrieved: " + data);
}
}

private JavaScriptBridge bridge;

@Override
public void start(Stage primaryStage) throws Exception {
WebView webView = new WebView();
primaryStage.setScene(new Scene(new AnchorPane(webView)));
primaryStage.show();

final WebEngine webEngine = webView.getEngine();
webEngine.load(getClass().getClassLoader().getResource("page.html").toExternalForm());

bridge = new JavaScriptBridge();
webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue == State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaApp", bridge);
}
});

webEngine.setOnAlert(event -> {
System.out.println(DATE_FORMAT.format(new Date()) + " alerted: " + event.getData());
});
}

Altough the code now works smoothly (also in conjunction with Leaflet), I am still irritated of this unexpected behaviour...

Edit: The explanation for this behaviour is documented since Java 9 (thanks @dsh for your clarifying comment! I was working with Java 8 at the time and unfortunately didn't have this information at hand...)

javafx webview does not display correctly an html page

Background on Test Environment

I ran some experimentations to determine what is causing (at least some of) your reported issues with the display of your provuded page.

For my tests I was using JavaFX 17.0.0.1 running Eclipse Temurin 17 JDK and Windows 10 Pro OS on MS Surface Book 2.

The sample webpage from your question displayed in Chrome 94 without the issues you note in your question, and in JavaFX WebView experienced the issues you note in your question.

To debug the issue, I added a console listener to the web engine, as demonstrated in the most popular answers to:

  • How to get the JavaFx WebEngine to report errors in detail?
  • WebConsoleListener IllegalAccessError in JavaFX 12

Once I did so, I saw the following error logged to the console:


Console: [https://cdn.jsdelivr.net/npm/chart.js:13] ReferenceError: Can't find variable: ResizeObserver

Information on ResizeObserver

Doing some research I could see that the ResizeObserver implementation isn't available for all browser implementations. So I guess it isn't implemented in WebView.

Information on ResizeObserver from Mozilla

  • https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver

Sample test page for ResizeObserver from Mozilla (I am not responsible for the weird text message in the sample):

  • https://mdn.github.io/dom-examples/resize-observer/resize-observer-text.html

Loading the sample page from mozilla in WebView confirms the issue with lack of support for ResizeObserver, with the following error printed when the WebConsoleListener is attached:


Console: [https://mdn.github.io/dom-examples/resize-observer/resize-observer-text.html:110] Resize observer not supported!

How to fix it

You can add the ResizeObserver ability to WebView (or other browsers which do not support the feature) via a polyfill.

The best way to fix it is to request the developers of the website you are using to integrate a polyfill for ResizeObserver into their website to allow it to be used on a wider variety of clients.

An example polyfill which fixes the issue is:

  • ResizeObserver polyfill.

If you download the source for the website you are using and import the polyfill JavaScript in the page before other items, then, most of the issues you reference in your question go away and work as expected on WebView:

  1. No error is displayed in the console regarding the ResizeObserver.
  2. The display automatically changes every 10 seconds.
  3. Graphs display when you click on the second circle.
  4. An image displays when you click on the third circle (though the image is larger than what I see on Chrome and clipped).

Polyfill javascript source for ResizeObserver:

  • https://github.com/que-etc/resize-observer-polyfill/blob/master/dist/ResizeObserver.js

Filing a feature request for ResizeObserver support for JavaFX WebView

If you wish, you can file a feature request for the JavaFX WebView requesting resize observer support.

To do so, you could subscribe to the openjfx-dev mailing list and post a message about this there, linking back to this question.

Or, file a bug report against JavaFX. If you do so, I'd advise referencing the mozilla resize observer test page and associated documentation rather than the test page in your original question.

Test Code

Must be run using the information from: this answer to allow access to an internal com.sun.javafx implementation.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import com.sun.javafx.webkit.WebConsoleListener;

public class WebViewPageLoad extends Application {
@Override
public void start(final Stage stage) {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();

engine.getLoadWorker().exceptionProperty().addListener((ov, t, t1) ->
System.out.println("Received exception: "+t1.getMessage())
);

WebConsoleListener.setDefaultListener((webViewReference, message, lineNumber, sourceId) ->
System.out.println("Console: [" + sourceId + ":" + lineNumber + "] " + message)
);

// test page from original question:
engine.load("http://it-topics.com/index3.html");
// test page for resize observer polyfill (functions as expected).
// engine.load("https://que-etc.github.io/resize-observer-polyfill/");
// canonical ResizeObserver test page from mozilla.
// engine.load("https://mdn.github.io/dom-examples/resize-observer/resize-observer-text.html");
// referencing a local hacked version of the it-topics.com index3.html.
// engine.load(WebViewPageLoad.class.getResource("it.html").toExternalForm());

VBox layout = new VBox(webView);

stage.setScene(new Scene(layout));
stage.show();
}

public static void main(String[] args) {
launch();
}
}


Related Topics



Leave a reply



Submit