I get a white page after filling in some forms and uploading a photo on https://indianvisaonline.gov.in/visa/index.html. I use JavaFX’s WebView to load the website. Everything works fine until I hit the photo upload button.
Filling in the form works perfectly fine with other browsers and was successful with Chrome, Firefox and Safari. Therefore I suspect it’s something specific to JavaFX’s WebView.
I tried ruling out any bugs by writing only the WebView part. Yet the white page is still displayed.
public class SimpleTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
WebView webView = new WebView();
webView.getEngine().load("https://indianvisaonline.gov.in/visa/indianVisaReg.jsp");
Scene scene = new Scene(webView);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
}
}
JavaFX WebEngine’s HTML 5 support
I notice the lack of HTML5 support compared to other browsers. JavaFX’s WebView (WebEngine) scores just 275 out of 555 points, whereas other browsers score way better. The things that I feel can break something is the lack of Web Cryptography API, Database storage, File Reading or limited ECMAScript 6 support. Yet I have no idea how to test this?
Testing with Firebug Lite
When embedding Firebug, something weird happens. Instead of showing a blank white page, it redirects me to the homepage. So Firebug can’t help me here either.
Debug
Trying to find something in the logs I added: -Djavax.net.debug=all. However this doesn’t return any errors either (like HTTPS related).
At this point I’d by happy with any advice!
On a project with JavaFX Webview we found the following useful:
webView.setContextMenuEnabled(true);
webView.getEngine().setOnError(event -> System.out.println(event.getMessage()));
webView.getEngine().setOnAlert(event -> System.out.println(event.getData()));
// local error console
com.sun.javafx.webkit.WebConsoleListener.setDefaultListener(
(webview, message, lineNumber, sourceId) -> System.out
.println("Console: [" + sourceId + ":" + lineNumber + "] " + message));
// Firebug lite
webView.getEngine().getLoadWorker().stateProperty().addListener(
(ChangeListener<State>) (ov, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
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');}");
}
});
webView.getEngine().locationProperty().addListener(
(observable, oldValue, newValue) -> System.out.println(newValue));
Also it seems the browser that behaves similarly to Webview is Safari. If something doesn't work on Safari it generally doesn't on Webview. Safari has better tools for development however.
Also you might pay attention to popups and sites that open new windows, this must be handled manually with Webview.
Related
The following code shows a weird behavior in JDK 9.0.1 (Windows):
Dialog Snippet
Dialog<Void> dialog = new Dialog<>();
WebView webView = new WebView();
dialog.getDialogPane().setContent(webView);
webView.getEngine().load("http://docs.oracle.com/javafx/");
dialog.show();
The WebView actually loads, but it does not render the web content to the GUI.
Proof Snippet
I had the following code (I edited it for simplicity sake)
private void loadSite(String url) throws IOException {
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
URI uri = URI.create(url);
Map<String, List<String>> headers = new HashMap<>();
CookieHandler.getDefault().put(uri, headers);
webEngine.getLoadWorker().stateProperty()
.addListener((observable, oldValue, newValue) -> {
System.out.println(newValue);
if (newValue == Worker.State.SUCCEEDED) {
System.out.println(cookieManager.getCookieStore().getCookies());
}
});
webEngine.load(url);
}
This snippet is used to print cookies from a fully loaded page. The worker reaches State.SUCCEEDED and the cookies get printed out, but the WebView doesn't render the web page.
Working Snippet
I tried the following snippet and it worked, the WebView actually renders the web page to the GUI:
Stage stage = new Stage();
final WebView webView = new WebView();
webView.getEngine().load("http://docs.oracle.com/javafx/");
stage.setScene(new Scene(webView));
stage.show();
The Dialog Snippet works with JDK 8 but not JDK 9.
Side by side comparison
Stage Snippet left, Dialog Snippet Right
Actual Question
Am I doing something wrong? why is this happening? I read some of the JDK 9 changes, but I didn't see anything relatable.
Thanks in advance for any colaboration.
I have similar issue with rendering content into a JfxPanel and it is rendering blank but HTML content can be printed in my java console. (I'm using JxBrowser but they are very similar)
I solved the issue by making the webEngine rendering Mode from Heavy Weight to Light Weight.
Essentially Swing/JavaFx components are light weight for the most part, if we stack a heavy weight component inside a light weight component it will have rendering problems.
Hope this helps!
I have got exactly the same issue. When I show the WebView in another context (e.g. in a TabView (within a Tab)) the HTML-file is shown properly. But when I use
dialog.getDialogPane().setContent(webView);
it is not. My code is pretty much the same as the Dialog Snippet above (except the location of the HTML-file) and I cannot figure out the problem.
Not even simple HTML with just one headline is displayed.
the problem I'm having is injecting some JavaScript into a WebView. I only have this problem on Android version 2.3.6 and below I'm assuming, don't have a test device lower than that though. My code works fine in Android 4+ so I'm not quite sure why it's failing. It seems to "submit" the form but doesn't fill out the username and password field in 2.3.6 so it always fails. My main goal is to simulate a form fill-out and submit in a WebView with two EditTexts so the user doesn't have to interact with the WebView itself. When the user hits the login button it runs this code:
//Set what needs to be filled out in the WebView
String javaScript = "(function(){ " +
"document.getElementById('user').value = '" + mUsername + "'; " +
"document.getElementById('password').value = '" + mPassword + "'; " +
"document.getElementById('form').submit(); " +
"})()";
//Load the javascript here
mWebView.loadUrl("javascript: " + javaScript);
I'm also setting my WebView settings to this:
//Setup the WebView options/settings
...
mWebView.getSettings().setSaveFormData(false);
mWebView.getSettings().setJavaScriptEnabled(true);
...
I've tried searching for any reason why this wouldn't work on 2.3.6 but haven't come up with anything. Is there some restriction in version 2.* that isn't present in 4+?
Edit: The button that runs the above code is only enabled once the page is finished loading. So when this button is clicked the above JS injection is run.
#Override
public void onPageFinished(WebView view, String url) {
...
//Only allow the user to inject the JS when the page has loaded
if(url.equals("...")
button.setEnabled(true);
...
}
SOLUTION: I'm not sure if this actually was the cause but changing the single quotes in the JS code to use double quotes seemed to make it run. Something like:
String javaScript = ... + "document.getElementById(\"user\").value = \"" + mUsername + "\"; "
There aren't any restrictions that I'm aware of but it's not uncommon to encounter issues stemming from differing Javascript engines in various versions of Android. It is likely simply a matter of trying different syntax to achieve the same result in an attempt to hit upon a version of the logic that makes that version of Javascript happy.
Including JQuery and writing your function using Jquery syntax might be a solution, too. As JQuery itself seems pretty good at dealing with these differences.
At which point in your flow does the JavaScript URL get loaded? Are you certain that at this time the DOM is loaded and the elements you reference are valid?
Do you see anything output in logcat when trying to execute the JavaScript? That should show JavaScript errors.
I'm looking for a way to do file uploads, with a custom progress bar, with google web toolkit. Not looking for a plugin which shows its own progress bar, I'm rather looking for something which will call my callback method and notify it of progress, so I can show my own progress bar.
If that's not possible, then I'd like to know how to access the HTML5 File API so I can build my own file uploader widget.
Any ideas?
Thanks.
There are many issues in GWT which makes difficult deal with this:
There is no FormData object in GWT, so you have to use JSNI to get one.
RequestBuilder does not support sending FormaData but only strings.
RequestBuilder does not support upload or download progress notifications.
FileUpload does not support the multiple attribute.
The Elemental package in GWT only works with webkit browsers, and I had some issues last time I tried to use the File Api.
Fortunately, gwtquery 1.0.0 has a bunch of features which facilitates to solve the problem.
Here you have a working example (with very few lines of code), which works in all browsers supporting the HTML5 file api:
import static com.google.gwt.query.client.GQuery.*;
[...]
final FileUpload fileUpload = new FileUpload();
RootPanel.get().add(fileUpload);
$(fileUpload)
// FileUpload does not have a way to set the multiple attribute,
// we use gQuery instead
.prop("multiple", true)
// We use gQuery events mechanism
.on("change", new Function() {
public void f() {
// Use gQuery utils to create a FormData object instead of JSNI
JavaScriptObject form = JsUtils.runJavascriptFunction(window, "eval", "new FormData()");
// Get an array with the files selected
JsArray<JavaScriptObject> files = $(fileUpload).prop("files");
// Add each file to the FormData
for (int i = 0, l = files.length(); i < l; i++) {
JsUtils.runJavascriptFunction(form, "append", "file-" + i, files.get(i));
}
// Use gQuery ajax instead of RequestBuilder because it
// supports FormData and progress
Ajax.ajax(Ajax.createSettings()
.setUrl(url)
.setData((Properties)form))
// gQuery ajax returns a promise, making the code more declarative
.progress(new Function() {
public void f() {
double total = arguments(0);
double done = arguments(1);
double percent = arguments(2);
// Here you can update your progress bar
console.log("Uploaded " + done + "/" + total + " (" + percent + "%)");
}
})
.done(new Function() {
public void f() {
console.log("Files uploaded, server response is: " + arguments(0));
}
})
.fail(new Function() {
public void f() {
console.log("Something went wrong: " + arguments(0));
}
});
}
});
Another option is to use gwtupload, which supports any browser, and it comes with some nice widgets and progress bar, even you can plug your own progress and status widgets.
It does not use HTML5 File api yet but an ajax solution based on a server listener. It will though, support html5 in future versions, falling back to ajax mechanism for old browsers. When gwtupload supports this, you wont have to modify anything in your code.
All the building blocks are in Elemental but might not work everywhere (Elemental is "close to the metal", without any support detection or hiding/working around browser bugs/discrepancies).
Or you can use JSNI.
I have been asked by my friend to make an application for Chrome and it requires me to have context-sensitive menus as below:
I have never really made anything for Chrome before and I have a few questions regarding it:
I will have to develop a plug-in, right ?
If so, is there a specific set of rules I have to follow ?
I know I can use GWT to compile Java to JavaScript
3. This context sensitive menu is the same as JPopupMenu ?
The application I want to develop is simple:
Copy some text,
right-click, click on the context sensitive menu
apply simple Caesar's cipher to the text
open a new JFrame with JtextArea in it to display the encrypted text.
What you're creating is called an "extension", not a "plug-in". A browser extension is written using HTML, CSS and Javascript, and got access to APIs for direct interaction with the browser.
Plug-ins, on the other hand, are compiled binaries such as Flash and Java.
Drop the idea of using GWT for Chrome extensions. It makes development of the extension harder, not easier (open issue).
Especially because you'll find plenty of vanilla JavaScript examples and tutorials in the documentation and Stack Overflow.
You just have to know the relevant APIs:
Copy some text,
right-click, click on the context sensitive menu
Use chrome.contextMenus. There's no need to copy, the selected text is available in the callback (examples).
apply simple Caesar's cipher to the text
Create a JavaScript function to achieve this.
open a new JFrame with JtextArea in it to display the encrypted text.
Create a new window using chrome.windows.create. You could include an extra HTML page in your extension, and use the message passing APIs to populate the text field, but since you appear to be a complete newbie, I show a simple copy-paste method to create and populate this window:
function displayText(title, text) {
var escapeHTML = function(s) { return (s+'').replace(/</g, '<'); };
var style = '*{width:100%;height:100%;box-sizing:border-box}';
style += 'html,body{margin:0;padding:0;}';
style += 'textarea{display:block;}';
var html = '<!DOCTYPE html>';
html += '<html><head><title>';
html += escapeHTML(title);
html += '</title>';
html += '<style>' + style + '</style>';
html += '</head><body><textarea>';
html += escapeHTML(text);
html += '</body></html>'
var url = 'data:text/html,' + encodeURIComponent(html);
chrome.windows.create({
url: url,
focused: true
});
}
Don't forget to read Getting started to learn more about the extension's infrastructure.
Check out Google Chrome Extensions Chrome Extensions
The Getting Started will help you Getting Started
You will find a section on how to use Context Menus.
I have a Java 7 program (using WebStart technology, for Windows 7/8 computers only).
I need to add a function so that my program clicks a button on a page with known URL (https).
Some people suggest WebKit SWT, but I went to their site and they say that the project was discontinued. (http://www.genuitec.com/about/labs.html)
Other people say that JxBrowser is the only option but it looks like it's over $1,300 which is crazy. (http://www.teamdev.com/jxbrowser/onlinedemo/)
I'm looking for something simple, free, lightweight, and able to open HTTPS link, parse HTML, access a button through DOM and click it. Perhaps some JavaScript too, in case there are JS handlers.
Thanks for your help.
You may be looking for HtmlUnit -- a "GUI-Less browser for Java programs".
Here's a sample code that opens google.com, searches for "htmlunit" using the form and prints the number of results.
import com.gargoylesoftware.htmlunit.*;
import com.gargoylesoftware.htmlunit.html.*;
public class HtmlUnitFormExample {
public static void main(String[] args) throws Exception {
WebClient webClient = new WebClient();
HtmlPage page = webClient.getPage("http://www.google.com");
HtmlInput searchBox = page.getElementByName("q");
searchBox.setValueAttribute("htmlunit");
HtmlSubmitInput googleSearchSubmitButton =
page.getElementByName("btnG"); // sometimes it's "btnK"
page=googleSearchSubmitButton.click();
HtmlDivision resultStatsDiv =
page.getFirstByXPath("//div[#id='resultStats']");
System.out.println(resultStatsDiv.asText()); // About 309,000 results
webClient.closeAllWindows();
}
}
Other options are:
Selenium: Will open a browser like Firefox and operate it.
Watij: Also will open a browser, but in its own window.
Jsoup: Good parser. No JavaScript, though.
Your question is kind of difficult to understand what you want. If you have a webstart app and want to open a link in the browser, you can use the java.awt.Desktop.getDesktop().browse(URI) method.
public void openLinkInBrowser(ActionEvent event){
try {
URI uri = new URI(WEB_ADDRESS);
java.awt.Desktop.getDesktop().browse(uri);
} catch (URISyntaxException | IOException e) {
//System.out.println("THROW::: make sure we handle browser error");
e.printStackTrace();
}
}