简体   繁体   中英

In Java, when we load HTML in WebView, how can we select an HTML element using the mouse?

The WebView control in JavaFX renders a URL and executes JavaScript (incl. jQuery). How can we select an element from the rendered WebView control on mouse over and get its Xpath on click?

I have tried to add mousemove, mouseenter, and mouseleave, but it matches multiple elements at the same time (parents and children). It should only add borders around one element.

Main app:

// main/visualuserinput/VisualUserInput.java
package visualuserinput;

import javafx.application.Platform;
import javafx.concurrent.Worker;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import visualuserinput.FileUtil;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;

public class VisualUserInput extends JFrame {

    private final JFXPanel jfxPanel = new JFXPanel();
    private WebEngine engine;

    private String url = "https://www.bezrealitky.cz/vyhledat?offerType=spolubydleni&estateType=byt&priceFrom=5000&priceTo=8000&disposition=&ownership=&construction=&equipped=&balcony=&order=timeOrder_desc&boundary=%5B%5B%7B%22lat%22%3A50.171436864513%2C%22lng%22%3A14.506905276796942%7D%2C%7B%22lat%22%3A50.154133576294%2C%22lng%22%3A14.599004629591036%7D%2C%7B%22lat%22%3A50.14524430128%2C%22lng%22%3A14.58773054712799%7D%2C%7B%22lat%22%3A50.129307131988%2C%22lng%22%3A14.60087568578706%7D%2C%7B%22lat%22%3A50.122604734575%2C%22lng%22%3A14.659116306376973%7D%2C%7B%22lat%22%3A50.106512499343%2C%22lng%22%3A14.657434650206028%7D%2C%7B%22lat%22%3A50.090685542974%2C%22lng%22%3A14.705099547441932%7D%2C%7B%22lat%22%3A50.072175921973%2C%22lng%22%3A14.700004206235008%7D%2C%7B%22lat%22%3A50.056898491904%2C%22lng%22%3A14.640206899053055%7D%2C%7B%22lat%22%3A50.038528576841%2C%22lng%22%3A14.666852728301023%7D%2C%7B%22lat%22%3A50.030955909657%2C%22lng%22%3A14.656128752460972%7D%2C%7B%22lat%22%3A50.013435368522%2C%22lng%22%3A14.66854956530301%7D%2C%7B%22lat%22%3A49.99444182116%2C%22lng%22%3A14.640153080292066%7D%2C%7B%22lat%22%3A50.010839032542%2C%22lng%22%3A14.527474219359988%7D%2C%7B%22lat%22%3A49.970771602447%2C%22lng%22%3A14.46224174052395%7D%2C%7B%22lat%22%3A49.970669964027%2C%22lng%22%3A14.400648545303966%7D%2C%7B%22lat%22%3A49.941901176098%2C%22lng%22%3A14.395563234671044%7D%2C%7B%22lat%22%3A49.948384148423%2C%22lng%22%3A14.337635637038034%7D%2C%7B%22lat%22%3A49.958376114735%2C%22lng%22%3A14.324977842107955%7D%2C%7B%22lat%22%3A49.9676286223%2C%22lng%22%3A14.34491711110104%7D%2C%7B%22lat%22%3A49.971859099005%2C%22lng%22%3A14.326815050839059%7D%2C%7B%22lat%22%3A49.990608728081%2C%22lng%22%3A14.342731259186962%7D%2C%7B%22lat%22%3A50.002211140429%2C%22lng%22%3A14.29483886971002%7D%2C%7B%22lat%22%3A50.023596577558%2C%22lng%22%3A14.315872285282012%7D%2C%7B%22lat%22%3A50.058309376419%2C%22lng%22%3A14.248086830069042%7D%2C%7B%22lat%22%3A50.073179111%2C%22lng%22%3A14.290193274400963%7D%2C%7B%22lat%22%3A50.102973823639%2C%22lng%22%3A14.224439442359994%7D%2C%7B%22lat%22%3A50.130060800171%2C%22lng%22%3A14.302396419107936%7D%2C%7B%22lat%22%3A50.116019827009%2C%22lng%22%3A14.360785349547996%7D%2C%7B%22lat%22%3A50.148005694843%2C%22lng%22%3A14.365662825877052%7D%2C%7B%22lat%22%3A50.14142969454%2C%22lng%22%3A14.394903042943952%7D%2C%7B%22lat%22%3A50.171436864513%2C%22lng%22%3A14.506905276796942%7D%2C%7B%22lat%22%3A50.171436864513%2C%22lng%22%3A14.506905276796942%7D%5D%5D&hasDrawnBoundary=1&mapBounds=%5B%5B%7B%22lat%22%3A51.58923530498002%2C%22lng%22%3A15.399838165986353%7D%2C%7B%22lat%22%3A51.58923530498002%2C%22lng%22%3A10.593319611298853%7D%2C%7B%22lat%22%3A49.626953225810375%2C%22lng%22%3A10.593319611298853%7D%2C%7B%22lat%22%3A49.626953225810375%2C%22lng%22%3A15.399838165986353%7D%2C%7B%22lat%22%3A51.58923530498002%2C%22lng%22%3A15.399838165986353%7D%5D%5D&center=%7B%22lat%22%3A50.618326631013446%2C%22lng%22%3A12.996578888642588%7D&zoom=8&locationInput=praha&limit=15";

    public VisualUserInput() {
        super();
        initComponents();

        getContentPane().add(jfxPanel);

        setSize(500, 500);
        // Kill everything on closing the frame
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    private void initComponents() {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                WebView view = new WebView();
                engine = view.getEngine();
                engine.setJavaScriptEnabled(true);
                engine.setOnAlert(event -> {
                    Alert alert = new Alert(Alert.AlertType.INFORMATION);
                    alert.setTitle("Custom Alert");
                    alert.setContentText(event.getData());
                    alert.showAndWait();
                });
                engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
                    if (Worker.State.SUCCEEDED.equals(newState)) {
                        Document doc = engine.getDocument();
                        Element styleNode = doc.createElement("script");
                        Text styleContent = null;
                        try {
                            styleContent = doc.createTextNode(FileUtil.gulp("test.js"));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        styleNode.appendChild(styleContent);
                    doc.getDocumentElement().getElementsByTagName("head").item(0).appendChild(styleNode);

                    System.out.println(engine.executeScript("document.documentElement.innerHTML"));
                    }
                });
                engine.load(url);

                Button btn2 = new Button();
                btn2.setText("JS action");
                btn2.setPrefSize(100, 100);
                btn2.setOnAction(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent event) {
                        engine.executeScript("testing()");
                    }
                });

                BorderPane borderPane = new BorderPane();
                borderPane.setTop(btn2);
                borderPane.setCenter(view);
                Scene scene = new Scene(borderPane);


                jfxPanel.setScene(scene);
            }
        });
    }

    public static void main(String[] args) {
        VisualUserInput main = new VisualUserInput();
        main.setVisible(true);
    }
}

FileUtil.java:

// main/visualuserinput/FileUtil.java
package visualuserinput;

import java.io.*;

public class FileUtil {
    public static String gulp(String filename) throws IOException {
        StringBuilder builder = new StringBuilder();
        try (InputStream stream = FileUtil.class.getClassLoader().getResourceAsStream(filename);
             InputStreamReader streamReader = new InputStreamReader(stream);
             BufferedReader reader = new BufferedReader(streamReader)) {
            for (String s = reader.readLine(); s != null; s = reader.readLine()) {
                builder.append(s).append(System.lineSeparator());
            }
        }

        return builder.toString();
    }
 }

test.js:

// resources/test.js

// inject jQuery when it's not loaded yet
if (typeof jQuery === "undefined") {
    var scriptTag = document.createElement("script");
    scriptTag.setAttribute("type", "text/javascript");
    scriptTag.setAttribute("src", "https://code.jquery.com/jquery-3.4.1.slim.min.js");
    document.getElementsByTagName("head")[0].appendChild(scriptTag);
}

$("html *").click(function (e) {
    e.preventDefault();
    var value = getXPath(this);
    alert(value);
    return false;
});


$("html *").mousemove(
    function (e) {
        e.preventDefault();
        $(this).mouseenter(function () {
            $(this).css("border", "3px solid red");
        });

        $(this).mouseleave(function () {
            $(this).css("border", "none");
        });
        return false;
    }
);


function getXPath(element) {
    var val = element.value;
    var xpath = '';
    for (; element && element.nodeType === 1; element = element.parentNode) {
        //alert(element);
        var id = $(element.parentNode).children(element.tagName).index(element) + 1;
        id > 1 ? (id = '[' + id + ']') : (id = '');
        xpath = '/' + element.tagName.toLowerCase() + id + xpath;
    }

    return xpath;
}

function testing() {
    alert("executed");
    var articles = $("article");
    for (var i = 0; i < articles.length; i++) {
        var article = $(articles[i]);
        article.addClass("ScraperTableRow");
        article.css("border", "3px solid yellow");
    }
}

The current result selects multiple elements and adds borders around them.

图片

The expected result should select one element and add borders around it. On click, it displays an alert with the XPath of selected element.

You need to stop the event from propagating up the tree.

See this example:

https://www.w3schools.com/jquery/event_stoppropagation.asp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM