iosjavafxrobovmgluon-mobilejavafxports

JavaFX WebView HyperLinks Cannot Be Disabled on Mobile Devices


The below code is used to disable hyperlinks in a JavaFX WebView object. However, when I run it on a mobile device it does not work, whilst it is working OK on desktop. Any alternative solution to affect mobile devices?

private void init() {
    webEngine = webView.getEngine();
    webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
      if(newState == State.SUCCEEDED && webEngine.getDocument() != null)
        disableHyperLinks(webEngine.getDocument());
    });
} // init()

private void disableHyperLinks(Document document) {
    NodeList nodeList = document.getElementsByTagName("a");
    for (int i = 0; i < nodeList.getLength(); i++)
    {
          Node node= nodeList.item(i);
          EventTarget eventTarget = (EventTarget) node;
          eventTarget.addEventListener("click", (evt) -> {
            evt.preventDefault();
          }, false);
    } // for
} // disableHyperLinks()

Solution

  • When you run on mobile, the WebView is not implemented with the JavaFX control, but instead the native one is used, both on Android and iOS.

    You can see here the implementation for Android, and here the one for iOS.

    On iOS there is no Document native method implemented, and it only returns the html content of the loaded page (providing that the content can be parsed, otherwise it will be null). So even if you are able to read and modify that content, it wouldn't have any effect over the real control.

    The good news is that you can use executeScript, as it is implemented for iOS.

    Something like this should work:

    private void init() {
        webEngine = webView.getEngine();
        webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
          if(newState == State.SUCCEEDED)
            disableHyperLinks();
        });
    } // init()
    
    private void disableHyperLinks() {
        Object res = webView.getEngine().executeScript("(function() { " +
                        "var links = document.getElementsByTagName(\"a\");\n" +
                        "    for (var i=0; i<links.length; i++) {\n" +
                        "        links[i].addEventListener(\"click\",function(e) {\n" +
                        "            e.preventDefault();\n" +
                        "        })\n" +
                        "    }"
                    + "return ('<html>'+ links.length +'</html>'); })();");
            if (res != null) {
                System.out.println("Hyperlinks disabled: " + res);
            } else {
                System.out.println("ERROR disabling hyperlinks");
            }
    } // disableHyperLinks()
    

    The above code won't work on Android, though. There is a (very hacky) possible way to do it, accessing the native control on runtime (but since the question is about iOS I won't explain here).