Android Lollipop WebView does not show <iframe> content - javascript

I receive from the server xhtml code which I want to show in Android app like ebook reader. For this the Monocle library was chosen.
Next I prepare webview with follow code:
contentView.addJavascriptInterface(new LectureJSInterface(), "Android");
contentView.getSettings().setAllowFileAccess(true);
contentView.getSettings().setJavaScriptEnabled(true);
contentView.setBackgroundColor(0xFFECECEC);
contentView.setWebChromeClient(new WebChromeClient());
contentView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Global.dismissProgressDialog();
}
});
After this I download the xhtml code from the server and add to it JS code for working with Monocle:
private String prepareCode(String code) {
if ((code == null) || code.equals("")) return "";
String newCode = code.substring(code.indexOf("<html"), code.indexOf("<head>")+6);
newCode = newCode.concat(
"<script src=\"file:///android_asset/monocore.js\"></script>\n" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"file:///android_asset/monocore.css\" />\n" +
"<style>\n" +
" #reader {\n" +
" width: 100%;\n" +
" height: 100%;\n" +
" border: 0px solid #000;\n" +
" }\n" +
"</style>\n" +
"<script>\n" +
"\n" +
" var isNightMode = false;\n" +
" var isFirstLoading = false;\n" +
" var startPageNumber = 1;\n" +
"\n" +
" function setSettingsForFirstLoading(fontSize, pageNumber, nightMode) {\n" +
" Android.printLogInfo('setSettingsForFirstLoading()');\n" +
" isFirstLoading = true;\n" +
" isNightMode = nightMode;\n" +
" startPageNumber = pageNumber;\n" +
" window.changeFontSize(fontSize);\n" +
" }\n" +
"\n" +
" function changeFontSize(fontSize) {\n" +
" Android.printLogInfo('changeFontSize()');\n" +
" window.reader.formatting.setFontScale(fontSize);\n" +
" }\n" +
"\n" +
" function nightModeOn() {\n" +
" Android.printLogInfo('nightModeOn()');\n" +
" isNightMode = true;\n" +
" var i = 0;\n" +
" var frame;\n" +
" while (frame = window.reader.dom.find('component', i++)) {\n" +
" frame.contentDocument.body.style.backgroundColor = '#1F1F1F';\n" +
" frame.contentDocument.body.style.color = '#ECECEC';\n" +
" }\n" +
" }\n" +
"\n" +
" function nightModeOff() {\n" +
" Android.printLogInfo('nightModeOff()');\n" +
" isNightMode = false;\n" +
" var i = 0;\n" +
" var frame;\n" +
" while (frame = window.reader.dom.find('component', i++)) {\n" +
" frame.contentDocument.body.style.backgroundColor = '#ECECEC';\n" +
" frame.contentDocument.body.style.color = '#1F1F1F';\n" +
" }\n" +
" }\n" +
"\n" +
" function turnPage(pageNumber) {\n" +
" Android.printLogInfo('turnPage(' + pageNumber + ')');\n" +
" window.reader.moveTo({ page: pageNumber });\n" +
" }\n" +
"\n" +
" function savePercents() {\n" +
" Android.printLogInfo('savePercents()');\n" +
" Android.savePercents(window.reader.getPlace().percentAtTopOfPage());\n" +
" }\n" +
"\n" +
" function moveToPercents(percent) {\n" +
" Android.printLogInfo('moveToPercents(' + percent + ')');\n" +
" turnPage(window.reader.getPlace().pageAtPercentageThrough(percent));\n" +
" }\n" +
"\n" +
" function listenFor(evtName) {\n" +
" Monocle.Events.listen('reader', evtName, report);\n" +
" }\n" +
"\n" +
" function report(evt) {\n" +
" switch (evt.type) {\n" +
" case 'monocle:loaded':\n" +
" Android.calculateSeekBar(window.reader.getPlace().properties.component.lastPageNumber());\n" +
" break;\n" +
"\n" +
" case 'monocle:turn':\n" +
" Android.updatePagesCounter(window.reader.getPlace().pageNumber());\n" +
" break;\n" +
"\n" +
" case 'monocle:recalculated':\n" +
" if (isNightMode) nightModeOn();\n" +
" if (isFirstLoading) { isFirstLoading = false; turnPage(startPageNumber); }\n" +
" Android.calculateSeekBar(window.reader.getPlace().properties.component.lastPageNumber());\n" +
" Android.updatePagesCounter(window.reader.getPlace().pageNumber());\n" +
" break;\n" +
" }\n" +
" }\n" +
"\n" +
" function init() {\n" +
" var options = {\n" +
" flipper: Monocle.Flippers.Slider\n" +
" }\n" +
"\n" +
" listenFor('monocle:turn');\n" +
" listenFor('monocle:loaded');\n" +
" listenFor('monocle:recalculated');\n" +
"\n" +
" window.reader = Monocle.Reader('reader', null, options);\n" +
" }\n" +
"\n" +
" Monocle.Events.listen(window, 'load', init);\n" +
"</script>\n");
newCode = newCode.concat(code.substring(code.indexOf("<head>") + 6, code.indexOf("<body>") + 6));
newCode = newCode.concat("<div id=\"reader\">");
newCode = newCode.concat(code.substring(code.indexOf("<body>") + 6, code.indexOf("</body>")));
newCode = newCode.concat("</div>");
newCode = newCode.concat(code.substring(code.indexOf("</body>")));
return newCode;
}
After finishing this task the WebView loads it:
contentView.loadDataWithBaseURL(baseUrl, prepareCode(code), "text/html", "UTF-8", null);
What I have as results? I tested this app on six devices with Android 4.x and 5.x. On Android 4.x the entire content is shown correctly, but on Android 5.x I see a blank page. I should notice that the xhtml code was loaded because I can call JS-functions and get its results via JS Interface.
Are there any ideas about ways to fixing this bug?
Thanks in advance!

You can try uninstalling the webview system update.
or
Try monocle 2.3.1
or
https://github.com/joseph/Monocle/issues/259

Related

Problems with displaying values of a property

So I'm trying to display the values of a book in myLibrary but the when I do it displays it like this :
Zero To one
Peter Thiel
210
Has been read already
function() { return title + " " + "by" + " " + author + " " + pages + " " + "pages" + " " + isRead; }
It shouldn't display this part:
function() { return title + " " + "by" + " " + author + " " + pages + " " + "pages" + " " + isRead; }
Here's my code:
this.pages = pages;
this.isRead = isRead;
this.info = function() {
return title + " " + "by" + " " + author + " " + pages + " " + "pages" + " " + isRead;
}
}
const zeroToOne = new Book("Zero To one", "Peter Thiel", "210", "Has been read already");
function addBookToLibrary(bookToAdd) {
myLibrary.push(bookToAdd);
console.log(myLibrary);
for (let obj of myLibrary) {
console.log(obj);
card.textContent = Object.values(obj);
}
}
You have to call the info function :
console.log(obj.info());

Why is Java (Nashnorn library) not evaluationg JS code correctly?

I have code that works fine in JavaScript IDE like Webstorm, but when I try to port it to Java, using the Nashorn library (to run JS within a Java program), I get these errors: "Name: undefined, Age: undefined" (with possibly others to follow depending what's wrong here.)
Below is the full code. This coding approach below seems to work in general, but there are cases like this where I don't get the expected results.
Would appreciate any help or suggestions.
Thanks!
public class JavaScriptEvaluationExample
{
public static void main(String[] args) throws ScriptException, NoSuchMethodException
{
// Basic JavaScript evaluation
String json = "{\n" +
" \"name\": \"John\",\n" +
" \"age\": 30,\n" +
" \"cars\": [\n" +
" {\n" +
" \"name\": \"Ford\",\n" +
" \"models\": [\n" +
" \"Fiesta\",\n" +
" \"Focus\",\n" +
" \"Mustang\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"name\": \"BMW\",\n" +
" \"models\": [\n" +
" \"320\",\n" +
" \"X3\",\n" +
" \"X5\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"name\": \"Fiat\",\n" +
" \"models\": [\n" +
" \"500\",\n" +
" \"Panda\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}";
String jsScript = "function parseJSONFields(param)\n" +
"{\n" +
" var result = \"\";\n" +
" var carName =\"\" ;\n" +
" var models = \"\";\n" +
" var name = param.name + \",\";\n" +
" var age = param.age;\n" +
" result = \"Name: \" + name + \" Age: \" + age + \"\\n\";\n" +
" for (item in param.cars)\n" +
" {\n" +
" result += \" \"+ \" >> \" + param.cars[item].name +\": \"\n" +
" result+= \" \" + param.cars[item].models\n" +
" result += \"\\n\";\n" +
" }\n" +
" return result;\n" +
"}";
System.out.println(runJS("parseJSONFields", json, jsScript));
}
// ------------------------------------------------------------------------------------------------
private static Object runJS(String functionName, String param, String script) throws ScriptException, NoSuchMethodException
// ------------------------------------------------------------------------------------------------
{
Object resultString = "";
String errorResultString = "";
ScriptEngine js = null;
try
{
if (param.length() > 0)
{
js = new ScriptEngineManager().getEngineByName("javascript");
js.eval(script);
Invocable inv = (Invocable) js;
}
}
catch (Exception e)
{
errorResultString = e.getMessage() + " ---> " + e.getMessage();
}
return errorResultString.length() > 0 ? errorResultString
: ((Invocable) js).invokeFunction(functionName, param);
}
}
Thanks to all who replied.
The problem was, as the first person noted, that I forgot the JSON.parse() statement to convert the string to a JSON object.
Thanks very much again.

How to make my .css and .js file work with my html code loaded in a WebView on Android

So I made a simple todo list in html and the .css and .js file I have associated with my .html file work properly in the browser. Now I am trying to make it work in a web view as an android app. I'm using AndroidStudio and have created an assets folder and added my .css and .js file to them. I copied all my html code into a string and am using loadWithBaseURL. Only my html loads in the web view without any style or functionality. Can someone point me in the right direction to get this working?
package com.android.todowebview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.app.Activity;
public class MainActivity extends Activity {
private WebView browser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
browser = (WebView) findViewById(R.id.webView1);
browser.getSettings().setJavaScriptEnabled(true);
String todoHtml = "<html>\n" +
" <head>\n" +
" <title>ToDoList</title>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html\" charset=\"UTF-8\"/>\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n" +
" <meta name=\"apple-mobile-web-app-cabable\" content=\"yes\"/>\n" +
" <link rel=\"stylesheet\" href=\"styles.css\"\n" +
" </head>\n" +
" <body>\n" +
" <head>\n" +
" <h1>\n" +
" ToDo-List\n" +
" </h1>\n" +
" </head>\n" +
" <form>\n" +
" <label>\n" +
" Title:\n" +
" <input id=\"newitem\" type=\"text\" placeholder=\"Tap to enter a new item…\">\n" +
" <br>\n" +
" Details:\n" +
" <input id=\"detail\" type=\"text\" placeholder=\"Details of new item…\">\n" +
" <br>\n" +
" Date:\n" +
" <input id=\"date\" type=\"date\" placeholder=\"year/month/day\">\n" +
" <br>\n" +
" Time:\n" +
" <input id=\"time\" type=\"time\" placeholder=\"00:00\">\n" +
" <br>\n" +
" </label>\n" +
" <button type=\"button\" id=\"additem\">\n" +
" Add\n" +
" </button>\n" +
" </form>\n" +
" <ul id=\"todo-list-container\">\n" +
" </ul>\n" +
" <!--\n" +
" <p id=\"total\">\n" +
" <span class=\"total1\">\n" +
" Total:\n" +
" <span id=\"totalcount\">\n" +
" 0\n" +
" </span>\n" +
" </span>\n" +
" <span class=\"remain\">\n" +
" Remaining:\n" +
" <span id=\"remaining\">\n" +
" 0\n" +
" </span>\n" +
" </span>\n" +
" </p>\n" +
" -->\n" +
" <fieldset>\n" +
" <button class=\"button deletechecked\" type=\"button\" id=\"delete-checked-items\">\n" +
" Delete Checked\n" +
" </button>\n" +
" <button class=\"button deleteall\" type=\"button\" id=\"delete-all-items\">\n" +
" Delete All\n" +
" </button>\n" +
" </fieldset>\n" +
"\n" +
" <script type=\"text/template\" id=\"item-template\">\n" +
" <li>\n" +
" <label>\n" +
" <input type=\"checkbox\">\n" +
" <!-- ITEM_NAME -->\n" +
" </label>\n" +
" </li>\n" +
" </script>\n" +
" \n" +
" <script src=\"todo_back.js\">\n" +
" </script>\n" +
" </body>\n" +
"</html>";
//browser.loadData(todoHtml, "text/html", "UTF-8");
browser.loadDataWithBaseURL("file:///android_asset", todoHtml, "text/html", "UTF-8", null);
}
}
For a testing purpose, or quick and dirty method, you may try to move your css file content inside a style tag, the js one in a script one, to avoid link/folder errors.

Posting from multiple dynamically created HTML textarea elements

Given the following snippet:
out.println("<form action=" + "./post" + " " + "method=" + "post" + " " + "id=" + "tweetForm" + ">");
for (int i = 1; i <= twParser.currentTweetIndex; i++) {
output = twParser.tweetArray[i] + newLine;
out.println("<p>");
out.println("<textarea" + " " + "name=text" + " " + "id=\"styled\"" + " " + "maxlength=140" + " " + "cols=" + "140" + " " + "rows=" + "1" + " " + "tag=" + "text_" + String.valueOf(i) + " " + "form=" + "tweetForm" + " " + "onfocus=\"setbg('#e5fff3');\" onblur=\"setbg('white')\"" + ">" + output + "</textarea>");
out.println("<span class=label-style-countdown" + " " + "id=" + "chars" + String.valueOf(i) + ">" + String.valueOf(140 - twParser.tweetArray[i].length()) + "</span> characters remaining");
out.println("<p>");
}
out.println("<input type=" + "submit" + " " + "name=" + "post" + " " + "value=" + "post" + " " + "style=\"float: left;\"" + "/>");
out.println("<button type=\"reset\" value=\"Reset\">Reset</button>"
...that creates HTML multiple textarea elements and posts them to a servlet. But since all the textareas have the same name, only the contents of the first textarea are posted.
Is there a way to post them all?
Thanks
To have multiple inputs from same name you can use name array like
<textarea name="text[]">You text here</textarea>
which will post all the values having same name as an array.
PS: This can be done with any input types expect radio buttons
On this line:
out.println("<textarea" + " " + "name=text" + " " ...
Append i to the name of the textarea, such that the names increase as text1, text2 etc.
out.println("<textarea" + " " + "name=text" + i.toString() + " " ...
Perform the same loop on the server when receiving the POST request to receive from each textarea.

Function in JavaScript that outputs concat url to YUI Chart Library Output

Trying to properly write a function in JavaScript that outputs a concat'd url to Chart Library Output (for chart re-rendering)... based on selected options in dropdown list.
Problem: I am not getting the chart to re-render with the concatenated url (which should be sent each time an option is selected in the dropdown).
JavaScript code in head:
function httpGet(theUrl)
{
var xmlHttp = null;
xmlHttp = new XMLHttpRequest(); // instantiate request
xmlHttp.open( "GET", theUrl, false ); // open url
xmlHttp.send( null ); // sending nothing
return xmlHttp.responseText; // return url's data as text
};
function selectFabric(){
var urlString = "http://localhost:8083/tbl/sparqlmotion?id=LiabilityChart&arg1=";
var fabrics = document.getElementById('fabrics');
var selectedFabric = fabrics.options[fabrics.selectedIndex];
var linkAddTogether = [urlString + selectedFabric.value];
var linkResult = linkAddTogether[0];
var result = httpGet(linkResult);
if (selectedFabric.value != "nothing"){
return linkResult; // update begins // document.write(linkAddTogether)
};
};
function revive (key, value) {
if (value.datatype == "http://www.w3.org/2001/XMLSchema#double" || // if datatype is this
value.datatype == "http://www.w3.org/2001/XMLSchema#integer" || // or, this
value.datatype == "http://www.w3.org/2001/XMLSchema#float") // or, this
{
return (parseInt(value.value)) // if '#double', '#integer', or '#schema', then: 'vars' label + convert the datatype's float value to integer
}
else if (value.type == 'literal')
{
return (value.value) // if datatype's value is a literal: 'vars' label + return as a string
}
else if (value.datatype == 'http://www.w3.org/2001/XMLSchema#date')
{
return value.value // if "XMLSchema#date's" value is a literal: 'vars' label + return as a string
}
else
{
return value // if datatype is anything else: 'vars' label + return value as a string
}
};
var scriptHead = ["YUI().use('charts',function(Y){var myDataValues=\n\n["];
var scriptTail = ["\n];\n\nvar styleDef={series:{Stock:{line:{color:'#EEB647'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#222',alpha:0,wmode:'transparent'},over:{fill:{color:'#eee'},border:{color:'#000'},width:9,height:9}}},Liability:{line:{color:'#171944'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#222',alpha:0,wmode:'transparent'},over:{fill:{color:'#eee'},border:{color:'#000'},width:9,height:9}}},Shipment:{line:{color:'#ff0000',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#ff0000',alpha:0,wmode:'transparent'},over:{fill:{color:'#ff0000',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}},Production:{line:{color:'#FFD700',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#FFD700',alpha:0,wmode:'transparent'},over:{fill:{color:'#FFD700',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}},Order:{line:{color:'#006400',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#006400',alpha:0,wmode:'transparent'},over:{fill:{color:'#006400',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}}}};var myAxes={dateRange:{keys:['date'],position:'bottom',type:'category',title:'Date Range',styles:{majorTicks:{display:'none'},label:{rotation:-45,margin:{top:5}},title:{fontSize:'90%'}}}};var mychart=new Y.Chart({dataProvider:myDataValues,interactionType:'planar',render:'#mychart',categoryKey:'Date',styles:styleDef,categoryType:'time',horizontalGridlines:{styles:{line:{color:'#fff'}}},verticalGridlines:{styles:{line:{color:'#fff'}}}})});\n\n"];
var simpleHead = [scriptHead];
var simpleTail = [scriptTail];
var oldData = JSON.parse(result, revive);
HTML code for form (in body):
form style="width:200px; color:#333; padding-right:5px; padding-bottom:2px; padding-left:55px; margin-top:0px; clear:none;" name="properties" id="properties">
select style="width:160px; color:#333; clear:none; display:block;" name="fabrics" id="fabrics" onChange="selectFabric()">
option value="nothing">Select Fabric END option
option value="KOD23-4074-LV">KOD23-4074-LV END option
option value="SGOD2-2858-LV">SGOD2-2858-LV END option
option value="W-897-LV">W-897-LV END option
option value="FF-4084-LV">FF-4084-LV END option
END select
END form
JavaScript code for chart (write script in body to render YUI chart plug-in):
document.write('\x3Cscript type="text/javascript" id="source">');
document.write(simpleHead[0] + '\n{Date: "' + oldData.results.bindings[0].date + '", Liability: ' + oldData.results.bindings[0].liability + ", Stock: " + oldData.results.bindings[0].stock + ", " + oldData.results.bindings[0].event + ": " + oldData.results.bindings[0].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[1].date + '", Liability: ' + oldData.results.bindings[1].liability + ", Stock: " + oldData.results.bindings[1].stock + ", " + oldData.results.bindings[1].event + ": " + oldData.results.bindings[1].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[2].date + '", Liability: ' + oldData.results.bindings[2].liability + ", Stock: " + oldData.results.bindings[2].stock + ", " + oldData.results.bindings[2].event + ": " + oldData.results.bindings[2].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[3].date + '", Liability: ' + oldData.results.bindings[3].liability + ", Stock: " + oldData.results.bindings[3].stock + ", " + oldData.results.bindings[3].event + ": " + oldData.results.bindings[3].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[4].date + '", Liability: ' + oldData.results.bindings[4].liability + ", Stock: " + oldData.results.bindings[4].stock + ", " + oldData.results.bindings[4].event + ": " + oldData.results.bindings[4].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[5].date + '", Liability: ' + oldData.results.bindings[5].liability + ", Stock: " + oldData.results.bindings[5].stock + ", " + oldData.results.bindings[5].event + ": " + oldData.results.bindings[5].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[6].date + '", Liability: ' + oldData.results.bindings[6].liability + ", Stock: " + oldData.results.bindings[6].stock + ", " + oldData.results.bindings[6].event + ": " + oldData.results.bindings[6].current + "}" + simpleTail[0] + "\n\n");
document.write('\x3C/script>');

Categories