Is it possible to open a browser using the WebDriver class in Selenium and get the elements that the user is clicking?
I already looked through the documentation of selenium and found nothing useful.
I already thought about inserting a javascript function into the webpage, that gets called whenever a clickable element is clicked, but I dont know how I would then retrieve that information into my java programm. Any ideas on how to solve this problem?
Managed to solve this problem with the hint that Saurabh Gaur gave me
Here is my HTML document that I tested the application with, its called Index.html:
<html>
<head>
<title>I am the title, haha!</title>
</head>
<body>
<p id="id1">I am id1</p>
end my suffering
<body>
</html>
and here is my java code. all it does is add a listener to the HTML elements:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws MalformedURLException {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.load(new File("PATH/TO/Index.html").toURI().toURL().toExternalForm());
Scene scene = new Scene(webView);
stage.setScene(scene);
stage.show();
//we need this to check if the document has finished loading, otherwise it would be null and throw a exception
engine.getLoadWorker().stateProperty().addListener((obs, oldState, currentState) -> {
if (currentState == State.SUCCEEDED) {
Document doc = engine.getDocument();
addListeners(doc);
}
});
}
private void addListeners(Document doc) {
Element link1 = doc.getElementById("id1");
((EventTarget) link1).addEventListener("click", e -> {
System.out.println("id1 was clicked!");
}, false);
Element link2 = doc.getElementById("ihatejava");
((EventTarget) link2).addEventListener("click", e -> {
System.out.println("ihatejava was clicked!");
}, false);
}
}
I am creating a sample app in JavaFx.
I have loaded a local html file in webview in app. I want to apply style to that loaded html page from the app. When i try to do that the style is applied to entire webview.
I only want to apply on that loaded html page not the webview.
This is index.html page that I am loading.
<!DOCTYPE html>
<html>
<head>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = "Paragraph changed.";
}
</script>
</head>
<body>
<h1>My Web Page</h1>
<p id="demo">A Paragraph</p>
<button type="button" onclick="myFunction()" id="btn">Try it</button>
</body>
</html>
This is demo.css
*{
padding: 0;
margin: 0;
}
#btn{
font-weight: bold;
font-size: 14px;
padding: 10px 20px;
}
body {
background-color: #00ff80;
font-family: Arial, Helvetica, san-serif;
}
This is my javafx app code.
Hyperlink hpl3 = new Hyperlink("Load Html File");
hpl3.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
String path = System.getProperty("user.dir");
path.replace("\\\\", "/");
path += "/html/index.html";
String path1 = System.getProperty("user.dir");
path1.replace("\\\\", "/");
path1 += "/css/demo.css";
webEngine.setUserStyleSheetLocation("file:///" + path1);
webEngine.load("file:///" + path);
}
});
As james-d said:
import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
public class WebViewCssPlay extends Application {
private static final String CSS =
"body {"
+ " background-color: #00ff80; "
+ " font-family: Arial, Helvetica, san-serif;"
+ "}";
#Override
public void start(Stage stage) {
stage.setTitle("CSS Styling Test");
stage.setWidth(300);
stage.setHeight(200);
WebView browser = new WebView();
WebEngine webEngine = browser.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == State.SUCCEEDED) {
Document doc = webEngine.getDocument() ;
Element styleNode = doc.createElement("style");
Text styleContent = doc.createTextNode(CSS);
styleNode.appendChild(styleContent);
doc.getDocumentElement().getElementsByTagName("head").item(0).appendChild(styleNode);
System.out.println(webEngine.executeScript("document.documentElement.innerHTML"));
}
});
webEngine.loadContent("<html><body><h1>Hello!</h1>This is a <b>test</b></body></html>");
VBox root = new VBox();
root.getChildren().addAll(browser);
root.getStyleClass().add("browser");
Scene scene = new Scene(root);
stage.setScene(scene);
//scene.getStylesheets().add("/net/snortum/play/web_view.css");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Source:
Applying CSS file to JavaFX WebView
This is the code for showing map on swing application with jxbrowser. But when i click on the button, "Uncaught ReferenceError: map is not defined" this error is shown. The application is showing the map. But the joom in out and marker button does not working. What should i do?
final Browser browser = new Browser();
BrowserView view = new BrowserView(browser);
JButton zoomInButton = new JButton("Zoom In");
zoomInButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (zoomValue < MAX_ZOOM) {
browser.executeJavaScript("map.setZoom(" + ++zoomValue + ")");
}
}
});
JButton zoomOutButton = new JButton("Zoom Out");
zoomOutButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (zoomValue > MIN_ZOOM) {
browser.executeJavaScript("map.setZoom(" + --zoomValue + ")");
}
}
});
JButton setMarkerButton = new JButton("Set Marker");
setMarkerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
browser.executeJavaScript("var myLatlng = new google.maps.LatLng(48.4431727,23.0488126);\n" +
"var marker = new google.maps.Marker({\n" +
" position: myLatlng,\n" +
" map: map,\n" +
" title: 'Hello World!'\n" +
"});");
}
});
JPanel toolBar = new JPanel();
toolBar.add(zoomInButton);
toolBar.add(zoomOutButton);
toolBar.add(setMarkerButton);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.add(toolBar, BorderLayout.SOUTH);
frame.setSize(900, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// Provide the correct full path to the map.html file, e.g. D:\\map.html
browser.loadURL("file:///E:/Programming/map.html");
and my map.html file:
<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapProp = {
center:new google.maps.LatLng(51.508742,-0.120850),
zoom:5,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="googleMap" style="width:850px;height:380px;"></div>
</body>
</html>
I suppose it happens because you didn't provide API_KEY for Google Maps API as described in the instruction at https://jxbrowser.support.teamdev.com/support/solutions/articles/9000012874-google-maps
Please replace the API_KEY string with your Google API KEY value:
https://maps.googleapis.com/maps/api/js?key=API_KEY&sensor=false
You cannot load the API once the page has already loaded.
google.maps.event.addDomListener(window, 'load', initialize);
You can check out some similar SO or this to get more guidance.
I have looked at many update Panel answers in SO but could not solve my problem. It is very straight forward and I don't know why I dont get the panel updated.
I have two panel created in the RadioChoicePage.java:
public class RadioChoicePage extends ApplicationPageBase{
private static final long serialVersionUID = 1L;
public TestPanel tp;
public static TextPanel txp;
public RadioChoicePage(){
tp = new TestPanel("testPanel");
txp = new TextPanel("textPanel");
txp.setMsg("Before");
add(tp);
add(txp);
}
}
The markup file looks like the following:RadioChoicePage.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<body>
<wicket:extend>
<div wicket:id="testPanel" style="position:absolute; left:10px ; width:50%; z-index:10;">
</div>
<div wicket:id="textPanel" style="position:absolute; left:450px; width:50%; z-index:5">
</div>
</wicket:extend>
</body>
</html>
The two panel are TestPanel.java and TextPanel.java. I have a TestPanel.js file adding svg using d3.js and clicking on a circle I want to update the text panel.
I am able to call the wicket method from javascript and print that the circle was clicked on the console. But I am not able to update the text Panel.
Below is the code for TestPanel.java, TestPanel.html, TestPanel.js , TextPanel.java and TextPanel.html.
TestPanel.java
public class TestPanel extends Panel{
public static final JavaScriptResourceReference TEST_JS = new JavaScriptResourceReference(
TestPanel.class, "TestPanel.js");
TextPanel ttxp = new TextPanel("textPanel");
public TestPanel(String id) {
super(id);
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {
private static final long serialVersionUID = 1L;
public void renderHead(Component component,IHeaderResponse aResponse){
super.renderHead(component, aResponse);
String componentMarkupId = component.getMarkupId();
String callbackUrl = getCallbackUrl().toString();
aResponse.render(JavaScriptReferenceHeaderItem.forReference(TEST_JS));
aResponse.render(JavaScriptReferenceHeaderItem.forReference(D3Reference.D3_JS));
aResponse.render(OnDomReadyHeaderItem.forScript("draw(" + componentMarkupId + ",\"" + callbackUrl + "\")"));
}
protected void respond(final AjaxRequestTarget target) {
//target.add(new Label("msg", "Yeah I was just called from Javascript!"));
System.out.println("I was succesfully clicked");
ttxp.setMsg("After");
target.add(ttxp);
}
};
add(behave);
}
}
TestPanel.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<head>
<wicket:head>
</wicket:head>
</head>
<body>
<wicket:panel>
<div id="chart" style="position:absolute; width:400px; height:400px; border:2px solid blue;"></div>
</wicket:panel>
</body>
</html>
TestPanel.js
function draw(componentMarkupId,callbackUrl){
console.log(" Draw is called!");
//Width and height
var w = 300;
var h = 100;
//Data
var dataset = [ 5, 10, 15, 20, 25 ];
//Create SVG element
var svg = d3.select("#chart")
.append("svg")
.attr("width", w)
.attr("height", h);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", h/2)
.attr("r", function(d) {
return d;
})
.attr("fill", "red")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;
});
circles.on("click",function(d){
this.style.stroke = "steelblue";
$(function() {
var wcall = Wicket.Ajax.get({ u:callbackUrl });
//var wcall = wicketAjaxGet('$callbackUrl$');
alert(wcall);
});
});
}
TextPanel.java
public class TextPanel extends Panel{
String msg;
boolean initialize = true;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public TextPanel(String id) {
super(id);
// TODO Auto-generated constructor stub
System.out.println(getMsg());
if(initialize){
setMsg("Before");
initialize = false;
}
Label mmsg = new Label("msg", getMsg());
add(mmsg);
setOutputMarkupId(true);
}
}
TextPanel.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<head>
<wicket:head>
</wicket:head>
</head>
<body>
<wicket:panel>
<div wicket:id="msg" style="border: 2px solid blue;"></div>
</wicket:panel>
</body>
</html>
Please do give me a solution with explanation. As I have read so many solutions and explanations on SO and other resources but I feel im missing something basic here.
You can copy the code exactly and run it to check whats the real problem. I do not get any errors but Panels simple dont get updated.
Thank you for taking time to read this huge question with a small problem.
RadioChoicePage's textPanel should not be static, otherwise the component will be shared between multiple sessions:
public TextPanel txp;
Why is TestPanel creating its own instance of TextPanel?
TextPanel ttxp = new TextPanel("textPanel");
Remove that! Add a hook method to TestPanel instead:
protected void onClicked(AjaxRequestTarget target) {
}
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {
protected void respond(final AjaxRequestTarget target) {
onClicked(target);
}
}
Let RadioChoicePage decide what to do when anything is clicked:
tp = new TestPanel("testPanel") {
protected void onClicked(AjaxRequestTarget target) {
target.add(txp);
}
};
txp = new TextPanel("textPanel");
txp.setOutputMarkupId(true);
How can I load JavaScript to a JavaFx Webview after $(document).ready(function() ie. after the webview loads and without waiting for events like onButtonClick action, for example?
The answer to this would answer my main question, How to add jQuery into a webview?.
I've been trying to make the following work but I've been unsuccessful at integrating other similar solutions online onto my problem.
The HTML file I'd like to add onto a webview is as follows:
<!DOCTYPE html>
<html>
<head>
<link href='../fullcalendar/fullcalendar.css' rel='stylesheet' />
<link href='../fullcalendar/fullcalendar.print.css' rel='stylesheet' media='print' />
<script src='../lib/jquery.min.js'></script>
<script src='../lib/jquery-ui.custom.min.js'></script>
<script src='../fullcalendar/fullcalendar.min.js'></script>
<script>
$(document).ready(function() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar').fullCalendar({
editable: true,
events: [
{
title: 'All Day Event',
start: new Date(y, m, 1)
},
{
title: 'Long Event',
start: new Date(y, m, d-5),
end: new Date(y, m, d-2)
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d-3, 16, 0),
allDay: false
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d+4, 16, 0),
allDay: false
},
{
title: 'Meeting',
start: new Date(y, m, d, 10, 30),
allDay: false
},
{
title: 'Lunch',
start: new Date(y, m, d, 12, 0),
end: new Date(y, m, d, 14, 0),
allDay: false
},
{
title: 'Birthday Party',
start: new Date(y, m, d+1, 19, 0),
end: new Date(y, m, d+1, 22, 30),
allDay: false
},
{
title: 'Click for Google',
start: new Date(y, m, 28),
end: new Date(y, m, 29),
url: 'http://google.com/'
}
]
});
});
</script>
<style>
body {
margin-top: 40px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
#calendar {
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
This is what I've been trying to do so far:
public class WebViewSample extends Application {
private Scene scene;
#Override
public void start(Stage stage) {
// create the scene
stage.setTitle("Web View");
scene = new Scene(new Browser(), 750, 500, Color.web("#666970"));
stage.setScene(scene);
scene.getStylesheets().add("WebViewSample/fullcalendar-1.6.4/fullcalendar/fullcalendar.css");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
//apply the styles
getStyleClass().add("browser");
// load the web page
webEngine.load("WebViewSample/fullcalendar-1.6.4/demos/default.html");
//add the web view to the scene
getChildren().add(browser);
}
private Node createSpacer() {
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
return spacer;
}
#Override
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
}
#Override
protected double computePrefWidth(double height) {
return 750;
}
#Override
protected double computePrefHeight(double width) {
return 500;
}
}
All I get from this is a blank white window, instead of something like the jQuery calendar plugin FullCalender being drawn on the window.
Thank you in advance.
Try using this:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="layout" content="main">
<meta name="viewport" content="width=device-width"/>
<title>Calendar</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0">
<link rel='stylesheet' href="fullcalendar.css" />
<script src="jquery.min.js"></script>
<script src="moment.min.js"></script>
<script src="fullcalendar.min.js"></script>
<script>
$(document).ready(function() {
// page is now ready, initialize the calendar...
$('#calendar').fullCalendar({
//events:"%EVENT_URL%",
allDaySlot: false,
header:
{
left: 'today prev next',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView:'agendaDay',
firstHour:'9',
minTime:'8:00',
weekends: true
});
});
</script>