Problem: I cant seem to find a way for javafx webengine to fire javascript function if I use a java String object with multiple line.
If I enter the following example in html: "asd" ENTER "qwe" in the input textArea then CLICK send button. The following java code wont run:
webEngine.executeScript("onRecieveMsg('" + msg + "')");.
But it will work if I don't use ENTER in input textArea.
Please help me
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Chat</title>
</head>
<script type="text/javascript">
function onSendMsg(){
var msg = document.getElementById("inputTextArea").value;
document.getElementById("inputTextArea").value = "";
java.onSendMsg(msg);
}
function onRecieveMsg(msg){
var msg = msg;
msg = document.getElementById("outputTextArea").value + msg;
document.getElementById("outputTextArea").value = msg + "\n";
}
</script>
<body>
<h1>Output</h1>
<textarea id="outputTextArea" rows="10" cols="50" readonly></textarea>
<h1>Input</h1>
<textarea id="inputTextArea" rows="4" cols="50"></textarea>
<button id="sendBtn" onclick="onSendMsg()">Send</button>
</body>
</html>
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class ViewFx extends Application {
//VARIABLES
private WebView webView;
private WebEngine webEngine;
private WebEngineListener webEngineListener;
private JsBridge jsBridge;
//CONTRUCTOR
//METHODS
#Override
public void start(Stage stage) {
webView = new WebView();
webEngine = webView.getEngine();
webEngine.load(getClass().getResource("view.html").toExternalForm());
jsBridge = new JsBridge();
webEngineListener = new WebEngineListener(jsBridge);
webEngine.getLoadWorker().stateProperty().addListener(webEngineListener);
stage.setScene(new Scene(webView));
stage.setWidth(600);
stage.setHeight(700);
stage.show();
}
//INNER CLASS
private class WebEngineListener implements ChangeListener<State> {
//VARIABLES
private JsBridge jsBridge;
private JSObject jsobj;
//CONSTRUCTOR
private WebEngineListener(JsBridge jsBridge) {
this.jsBridge = jsBridge;
}
//METHODS
#Override
public void changed(ObservableValue<? extends State> observable, State oldState, State newState) {
if(newState == State.SUCCEEDED) {
jsobj = (JSObject) webEngine.executeScript("window");
jsobj.setMember("java", jsBridge);
}
}
}
public class JsBridge {
//VARIABLES
//CONTRUCTOR
//METHODS
public void onSendMsg(String msg) {
webEngine.executeScript("onRecieveMsg('" + msg + "')");
}
}
public static void main(String[] args) {
launch(args);
}
}
Multiline string literals neither work in JavaScript nor in java. In case of a multiline message being received you simply execute invalid JavaScript code:
message received
asd
qwe
Executed javascript
onRecieveMsg('asd
qwe')
You need to escape newline instead of including them in the script. There are a few more characters that require being quoted. You could use a method like this to get a properly quoted string:
public static String toJavaScriptString(String value) {
value = value.replace("\u0000", "\\0")
.replace("'", "\\'")
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
return "\""+ value+"\"";
}
Related
So I tried to get the value of an input type into a string in my android webview. But I couldnt find a way. Below is my code in the html.
<input class="input100" type="hidden" id="captcha1" name="captcha1" value="<?php echo $_SESSION['captcha']; ?>">
And i wanted to get the value and store it into a string in my android webview. Any clue??
You have to register javascript interface to webview. You can add methods with annotaion #JavascriptInterface to android webview controller that can be called from Webview controll. Also don't forgate to remove those from proguard...
for more info How to get return value from javascript in WebView of Android?
This example will read from html text and put in android text view.
You should be always carefullwhile exposing android method to webview java script
import android.content.Context
import android.util.Log
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.TextView
class MyWebView(context:Context, textView: TextView) {
var outValue:String =""
val myWebView = WebView(context)
val html: String by lazy{"<!DOCTYPE html><head><title>Loading...</title></head><body>"+
"<input type=\"text\" id=\"captcha1\" name=\"captcha1\" onkeyup=\"fromAndroid.getData(value);\">"+
"<img src= /></body></html>"}
init {
val javaScriptInterface = object: JavaScriptInterface{
#JavascriptInterface
override fun getData(data: String){
outValue = data
textView.text = data
Log.d(TAG, data)
}
}
myWebView.settings.setJavaScriptEnabled(true)
myWebView.addJavascriptInterface(javaScriptInterface, "fromAndroid")
myWebView.loadDataWithBaseURL("", html, "text/html","UTF-8", null);
}
companion object{
const val TAG = "MyWebView"
}
}
interface JavaScriptInterface{
fun getData(data: String)
}
You can use something similar in your code, The function from javascript must return the value and then it will be caught here as follows:
override fun onCreate(savedInstanceState: Bundle?) {
// webView referenced from layout id
webView.settings.javaScriptEnabled = true
webView.webViewClient = MyWebViewClient()
webView.setWebChromeClient(MyWebChromeClient())
webView.loadUrl("http://foobar.com")
}
private class MyWebViewClient : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
//functionToReturnSomething() should be \ same as you mention in javascript
view.loadUrl("javascript:alert(functionToReturnSomething())")
}
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
return false
}
}
private class MyWebChromeClient : WebChromeClient() {
override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean {
result.confirm()
return true
}
}
HI I am trying the example given in spring.io getting started guide.
it doesn't show any error but I am not getting HTML view
when I open the link http://localhost:8070/testJson in my browser all it shows is a JSON output like this
{"id":1,"content":"Hello World !"}
But I want it to show a proper HTML view, and I can not use #Controller here, I want to show HTML using Jquery javascript, How can I do that?
here is my controller method
#RestController
public class MyRestController {
private final Long counter = 1l;
#GetMapping("/testJson")
public TestJsonDto getTestJson(){
TestJsonDto testJsonDto=new TestJsonDto(counter,
"Hello World !");
return testJsonDto;
}
}
This is my Data class
public class TestJsonDto {
private Long id;
private String content;
public TestJsonDto(Long id, String content) {
this.id = id;
this.content = content;
}
public TestJsonDto() {
}
/*
GETTERS AND SETTERS WILL GO HERE
*/
And Below is my application class
#SpringBootApplication
#EnableJpaRepositories
public class MyjarApplication {
public static void main(String[] args) {
SpringApplication.run(MyjarApplication .class, args);
}
}
My Html file is
<!DOCTYPE html>
<html>
<head>
<title>Hello jQuery</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
<script src="/my.js"></script>
</head>
<body>
<div>
<p class="greeting-id">The ID is </p>
<p class="greeting-content">The content is </p>
</div>
</body>
</html>
and finally, this is my javascript
$(document).ready(function() {
$.ajax({
url: "http://localhost:8070/testJson"
}).then(function(testJsonDto) {
$('.greeting-id').append(testJsonDto.id);
$('.greeting-content').append(testJsonDto.content);
});
});
my application.properties is here
server.port=8070
Location of my.js is under src/main/resources/static/my.js
If you want to add a front end that can interact with your API you can structure your app like this:
This code setup your application, including static resources, for instance your resource/static/index.html will be render for root path localhost:8090 unless you wire this path in any controller(make sure root is not implicitly/explicitly user in any other #Controller or annotation).
#SpringBootApplication
#EnableJpaRepositories
public class MyjarApplication {
public static void main(String[] args) {
SpringApplication.run(MyjarApplication .class, args);
}
}
So, a simple way to render the HMTL you want is by putting that HTML at resource/static/index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello jQuery</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
<script src="/my.js"></script>
</head>
<body>
<div>
<p class="greeting-id">The ID is </p>
<p class="greeting-content">The content is </p>
</div>
</body>
</html>
and js should be placed at resource/static/my.js:
$(document).ready(function() {
$.ajax({
url: "http://localhost:8070/testJson"
}).then(function(testJsonDto) {
$('.greeting-id').append(testJsonDto.id);
$('.greeting-content').append(testJsonDto.content);
});
});
In your rest controller, path /testJson will be attended by getTestJson():
#RestController
public class MyRestController {
private final Long counter = 1l;
#GetMapping("/testJson")
public TestJsonDto getTestJson(){
TestJsonDto testJsonDto=new TestJsonDto(counter,
"Hello World !");
return testJsonDto;
}
}
So you access localhost:8090 to get the front-end, and thru javascript you access localhost:8090/testJson to get your API.
Below I attached the code to be executed with webview.
NOTE: JAVASCRIPT SHOULD BE ENABLED
ANYONE HELP ME TO RUN THIS HTML STRING IN WEBVIEW
<!DOCTYPE html>
<html>
<body>
<!-- Markup for HTML (Factors in Placement and Enrollment of Primary
Care Patientsin YMCA's Diabetes Prevention Program, Bronx, New
York,2010-2015) --><div class='rid_08184eef_309335'
data-apiroot='//tools.cdc.gov/api' data-mediatype='html'
data-mediaid='309335' data-stripscripts='true' data-stripanchors='false'
data-stripimages='false' data-stripcomments='true'
data-stripstyles='true' data-cssclasses='syndicate' data-ids=''
data-xpath='' data-oe='utf-8' data-of='xhtml' data-ns='cdc'
data-postprocess='' data-nw='true' data-iframe='true'
data-cdc-widget='syndicationIframe'
data-apiembedsrc='skins/larry//tools.cdc.gov/api/embed/html/js/embed-2.0.3.js'
data-iframeembedsrc='skins/larry//tools.cdc.gov/TemplatePackage/contrib/widgets/tp-widget-external-loader.js'></div><script
src='skins/larry//tools.cdc.gov/TemplatePackage/contrib/widgets/tp-widget-external-loader.js'
></script><noscript>You need javascript enabled to view this content or go to <a href='skins/larry//tools.cdc.gov/api/v2/resources/media/309335/noscript'>source URL</a>.</noscript>
</body>
</html>
I followed this link for basic setup. Nothing helped
BELOW I ATTACHED MY JAVA CODE
public class WebtestActivity extends Activity {
WebView webtest;
final Activity activity = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.webviewtesting);
webtest=(WebView)findViewById(R.id.webtest);
String htmlString = "<!-- Markup for HTML (How to Prevent Cancer or Find It Early) --><div class=\"rid_ec9fb40c_123238\" data-apiroot=\"//tools.cdc.gov/api\" data-mediatype=\"HTML\" data-mediaid=\"123238\" data-stripscripts=\"false\" data-stripanchors=\"false\" data-stripimages=\"false\" data-stripcomments=\"false\" data-stripstyles=\"false\" data-cssclasses=\"syndicate\" data-ids=\"\" data-xpath=\"\" data-oe=\"UTF-8\" data-of=\"XHTML\" data-ns=\"\" data-postprocess=\"\" data-nw=\"true\" data-iframe=\"true\" data-cdc-widget=\"syndicationIframe\" data-apiembedsrc=\"//tools.cdc.gov/api/embed/html/js/embed-2.0.3.js\" data-iframeembedsrc=\"//tools.cdc.gov/TemplatePackage/contrib/widgets/tp-widget-external-loader.js\" data-font=\"\"></div><script src='//tools.cdc.gov/TemplatePackage/contrib/widgets/tp-widget-external-loader.js' ></script><noscript>You need javascript enabled to view this content or go to <a href='//tools.cdc.gov/api/v2/resources/media/123238/noscript'>source URL</a>.</noscript>";
webtest.getSettings().setJavaScriptEnabled(true);
webtest.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress)
{
activity.setTitle("Loading...");
activity.setProgress(progress * 100);
if(progress == 100)
activity.setTitle(R.string.app_name);
}
});
webtest.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
{
// Handle the error
Log.d("des===",description);
Log.d("failingUrl===",failingUrl);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
Log.d("shouldlLoading===",url);
view.loadUrl(url);
return true;
}
});
webtest.loadData(htmlString, "text/html", null);
}
}
try this code. If you are learning, use official docs > WebView
String htmlString = "<html><body>Your text.</body></html>";
browser.getSettings().setJavaScriptEnabled(true);
browser.loadData(htmlString, "text/html", null);
Your code working fine. I attached screenshot
I've used the code example posted here calling date picker from javascript and this works fine in the android emulator. When I click on the date input box in web view, the android date picker appears and I can select it.
However, when I test this on my device, I just get a standard text input field it is as though the method is not being called. Does anyone have any suggestions? The full code I am using is:
public class MainActivity extends ActionBarActivity {
public WebView mWebView;
#Override
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.activity_main_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
final MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this);
mWebView.addJavascriptInterface(myJavaScriptInterface, "MyJavaScriptInterface");
mWebView.loadUrl("http:// mywebsite.html");
}
// Classe de prise en charge du java privé
public class MyJavaScriptInterface {
public String m_szTagId;
Context mContext;
MyJavaScriptInterface(Context c) {
mContext = c;
}
public void openDatePickerDialog(String szTagId) {
m_szTagId = szTagId;
Calendar c = Calendar.getInstance();
DatePickerDialog dp = new DatePickerDialog(mContext, new OnDateSetListener() {
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
String szDate = String.format("%04d/%02d/%02d", year, monthOfYear + 1, dayOfMonth);
mWebView.loadUrl("javascript:callFromActivity_RetDate(\"" + m_szTagId + "\", \"" + szDate + "\")");
}
}, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
dp.show();
}
} // Class MyJavaScriptInterface
#Override
public boolean onCreateOptionsMenu (Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
and the Javascript code is:
// ---- date picker to call methods of the android device
$('#datepicker').click(function(e){
getDataDate();
});
function getDataDate(){
MSSAndroidFunction.openDatePickerDialog('datepicker');
}
function callFromActivity_RetDate(datepicker, data) {
document.subHours.datepicker.value = data;
}
You have named your JavaScript Interface as MyJavaScriptInterface, so you must call it from JavaScript.
I.e.:
Instead of MSSAndroidFunction.openDatePickerDialog('datepicker'), you must do MyJavaScriptInterface.openDatePickerDialog('datepicker'), in a JavaScript method.
I have a WebView based application, in which I define the Interface in another class, not an inner class, and in the initialization I do:
htmlInterface=new HTMLInterface(this, webView);
webView.addJavascriptInterface(htmlInterface, "Android");
Hope it helps you
Regards
I'm using p:remoteCommand,its working fine for update and process except its not invoking either action method nor actionListener
Xhtml Code
<h:form id="mainForm">
<h:outputLabel id="tempAge" value="#{remoteBean.tempAge}"/>
<h:inputText id="age" value="#{remoteBean.age}" onkeypress="callRem()">
<f:validateLongRange minimum="18"/>
</h:inputText>
<script type="text/javascript">
var timex=0;
function callRem(){
clearTimeout(timex);
timex = setTimeout("remote()",2000);
}
</script>
<p:remoteCommand name="remote"
process="age"
update="tempAge"
action="#{remoteBean.act}"
actionListener="#{remoteBean.listen}">
</p:remoteCommand>
</h:form>
Managed Bean Code
#ManagedBean
public class RemoteBean {
private int age=18;
private int tempAge=20;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("Setting age :"+age);
}
public int getTempAge() {
return tempAge;
}
public void setTempAge(int tempAge) {
this.tempAge = tempAge;
}
public void act(){
System.out.println("in action()");
tempAge+=age+2;
}
public void listen(ActionEvent event) {
System.out.println("in Action Listener");
tempAge+=age+2;
}
}
I can't figure out where I'm doing wrong, may be its the Javascript code i've written.
If anyone faces and solved same issue please help.
Using: Primefaces 3.5
I tried yours example and found problem.
Seemse when you processing only age (process="age"), it executes only age input and ignores remoteCommand actionListener and action.
So you can change it to:
process="#form"
or
process="#this age"
worked both for me.
ps. I used View scope here.