This question already has answers here:
Custom JSF component: Using "startElement" with "script" results in a comment
(2 answers)
Closed 7 years ago.
i try to put internal JS code into a JS block. This should be done by a custom Renderer for the h:commandButton. The Renderer is inbound and works finde. But as soon as i start to generate the script block it is put between <!-- and -->.
So here is the method for generating the script block:
private void writeScript(FacesContext ctx, HtmlCommandButton button, String event, String script) throws IOException {
String nonce = UUID.randomUUID().toString();
ResponseWriter writer = ctx.getResponseWriter();
ctx.setResponseWriter(writer);
writer.startElement("input", button);
writer.writeAttribute("type", "submit", null);
writer.endElement("input");
writer.startElement("script", button);
writer.writeAttribute("nonce", nonce, null);
writer.write("document.getElementById('" + button.getClientId()
+ "')."
+ event
+ " ="
+ " function() {"
+ script
+ "}");
writer.endElement("script");
}
Also using the startCDATA() method doesn't seem to work.
So instead of:
<script nonce="...">
document.getElementById('j_id1955899975_7494aa2f:submitButton').alert('hallo') = function() {onclick}
</script>
the generated code looks like:
<script nonce="...">
<!--
document.getElementById('j_id1955899975_7494aa2f:submitButton').alert('hallo') = function() {onclick}
//-->
</script>
What am I doing wrong ?
Would be really nice if someone could help me :D
According to Predrag Maric's link i changed code to the following:
private void writeScript(FacesContext ctx, HtmlCommandButton button, String event, String script) throws IOException {
System.out.println("das event: "+event);
String nonce = UUID.randomUUID().toString();
ResponseWriter writer = ctx.getResponseWriter();
ctx.setResponseWriter(writer);
writer.startElement("input", button);
writer.writeAttribute("type", "submit", null);
writer.writeAttribute("id", button.getClientId(), null);
writer.endElement("input");
writer.write("<script>");
writer.write("document.getElementById('" + button.getClientId()
+ "')."
+ event
+ " ="
+ " function() {"
+ script
+ "}");
writer.write("</script>");
}
The problem was writing the script tags with the writeElement() method of the ResponseWriter It automatically adds the comments... After coding it out it works, thx a lot !.
Related
i need to be able to capture user's password and then bypass it if user authorized with biometrics to Android WebView. I'm successfully capturing the password and passing it to the webview, I'm executing the js like this, the method returns me js with injected css selector and value to input which I run against the webview
fun getJsToEnterValueToTextField(cssSelectorById: String, value: String): String {
val js = "javascript:(function() { " +
"var element = document.getElementById(\"$cssSelectorById\");" +
"console.log(element);" +
"element.value='${value.trim()}';" +
" element.dispatchEvent(new Event('input', {\n" +
" view: window,\n" +
" bubbles: true,\n" +
" cancelable: true\n" +
" }))" +
"})()"
Timber.d("SWA_WEBVIEW - getJsToEnterValueToTextField >> $js")
return js
}
//--//
webview.loadUrl(url2load)
The problem happens if the user has any escape characters in the value,
for example if user has '%E9' as part of that password string, once I run that js > this %E9 would transform to é
Does anyone know if there is a way around it? I searched all over but nothing seems to make a difference.
I know that plenty of similar questions can be found here but none of them could help me with my problem.
What the client wants: click on a button, then open a new window with given parameters and show a view with dynamic data loaded from database.
What I have done so far:
I have a view with links, not buttons:
<a th:href="#{/report/reportPrintView(al=false, mlVersion=${report.version}, sv=true, id=${report.orderId})}" target="_blank">Protokoll</a>
<a th:href="#{/report/reportPrintView(al=true, mlVersion=${report.version}, sv=false, id=${report.orderId})}" target="_blank">Airline</a>
and a controller which is called by the GET request:
#GetMapping("/report/reportPrintView")
public String showReportPrint(#RequestParam("al") boolean al, #RequestParam("mlVersion") String mlVersion, #RequestParam("sv") boolean sv, #RequestParam("id") String id, Model model) {
........ do some magic .......
return "/report/reportPrintView";
}
The view is displayed in a new browser tab and works as expected, but as said before, the client wants a new window.
To get a solution for the clients wishes I tried something like this:
function openWin(id, mlVersion, al, sv) {
var url = "/report/reportPrintView.html?al=" + al + "&mlVersion=" + mlVersion + "&sv=" + sv + "&id=" + id;
ReportPrintPreview = window.open("about:blank", "ReportPrintPreview", "width=666,height=700left=250,top=50,dependent=yes,menubar=no,status=no,resizable=yes,toolbar=no,scrollbars=yes");
ReportPrintPreview.location.href = url;
ReportPrintPreview.focus();
return false;
}
.
.
.
<button th:onclick="'openWin(\'' + ${report.orderId} + '\', \'' + ${report.version} + '\', false, true)'">Protokoll</button>
<button th:onclick="'openWin(\'' + ${report.orderId} + '\', \'' + ${report.version} + '\', true, false)'">Airline</button>
What happens here is that a new window is opened with a 404 error and the web page with the button shows a 400 error. So I assume that the controller doesn't get the GET request and cannot show the view (as is a reasonable result because it's not a Thymeleaf call like #{/report/....}).
Is there any way to get this running?
This is how I would structure that.
JavaScript
function openWin(url) {
ReportPrintPreview = window.open("about:blank", "ReportPrintPreview", "width=666,height=700left=250,top=50,dependent=yes,menubar=no,status=no,resizable=yes,toolbar=no,scrollbars=yes");
ReportPrintPreview.location.href = url;
ReportPrintPreview.focus();
return false;
}
Thymeleaf
<button
th:data-url="#{/report/reportPrintView(al=false, mlVersion=${report.version}, sv=true, id=${report.orderId})}"
onclick="openWin(this.getAttribute('data-url'))">Protokoll</button>
<button
th:data-url="#{/report/reportPrintView(al=true, mlVersion=${report.version}, sv=false, id=${report.orderId})}"
onclick="openWin(this.getAttribute('data-url'))">Airline</button>
For thymeleaf it works in different way. try below.
th:target="_blank"
I try to get the height of the actual HTML content inside my WebView in order to set the height according to the content.
this is my script, but I get an empty string when the scripit is being invoked.
private async Task LoadHTMLContent(ItemViewModel itemVm)
{
var htmlScript = "<script>function getDocHeight() { " +
"return document.getElementById('pageWrapper').offsetHeight; } </script>";
var htmlConcat = string.Format("<html><head>{0}</head>" +
"<body style=\"margin:0;padding:0;\" " +
">" +
"<div id=\"pageWrapper\" style=\"width:100%;" +
"\">{1}</div></body></html>", htmlScript, itemVm.Model.Content);
webView.NavigationCompleted += webView_NavigationCompleted;
webView.NavigateToString(htmlConcat);
}
async void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
string pageContentHeight = await webView.InvokeScriptAsync("getDocHeight", null);
}
Well, I found a solution.
If you wish to do the same, feel welcome to check out my solution on GitHub:
https://github.com/romshiri/sizeable-webview
I want to load a webpage in WebView but remove parts of the webpage. So, I created a custom WebViewClient. And, in onPageFinished(), I did some javascript to remove some elements. Then, I made the WebView visible.
However, when I run it, it sets the view visible, and then I see the elements being removed. It is as if the JS is running in the background very slowly. It creates a poor viewing experience because it flashes the full page and then the desired partial page.
Here is my onPageFinished()
#Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:"
+ "document.getElementsByClassName('header')[0].style.display='none';"
+ "document.getElementById('section_0').style.display='none';"
+ "document.getElementById('page-actions').style.display='none';"
+ "document.getElementsByClassName('languageSelector')[0].style.display='none';"
+ "document.getElementById('mw-mf-last-modified').style.display='none';"
+ "document.getElementById('footer').style.display='none';");
loadingView.setVisibility(View.INVISIBLE);
view.setVisibility(View.VISIBLE);
}
Any ideas on how to fix this?
In onPageFinished():
view.loadUrl("javascript:"
+ "var FunctionOne = function () {"
+ " var r = $.Deferred();"
+ " try{document.getElementsByClassName('header')[0].style.display='none';}catch(e){}"
+ " try{document.getElementById('section_0').style.display='none';}catch(e){}"
+ " try{document.getElementById('page-actions').style.display='none';}catch(e){}"
+ " try{document.getElementsByClassName('languageSelector')[0].style.display='none';}catch(e){}"
+ " try{document.getElementById('mw-mf-last-modified').style.display='none';}catch(e){}"
+ " try{document.getElementById('footer').style.display='none';}catch(e){}"
+ " setTimeout(function () {"
+ " r.resolve();"
+ " }, 2500);"
+ " return r;"
+ "};"
+ "var FunctionTwo = function () {"
+ " window.CallToAnAndroidFunction.setVisible();"
+ "};"
+ "FunctionOne().done(FunctionTwo);");
In MainActivity.onCreate():
this.webView.addJavascriptInterface(new JsObject(webView, loadingView), "CallToAnAndroidFunction");
In MainActivity():
public class JsObject {
private View loadingView;
private View view;
JsObject(View view, View loadingView){this.view = view;this.loadingView = loadingView;}
#JavascriptInterface
public void setVisible(){
runOnUiThread(new Runnable() {
#Override
public void run() {
view.setVisibility(View.VISIBLE);
loadingView.setVisibility(View.INVISIBLE);
}
});
}
}
So, it was a combination of making a JavascriptInterface and making a JS function to wait for the JS calls to finish before calling the interface (with the visibility settings).
You could try to speed up your WebView with:
webview.getSettings().setRenderPriority(RenderPriority.HIGH);
webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
Anyways, you shouldn't be making your WebView visible right away. Why don't you create an Interface (refer to http://developer.android.com/guide/webapps/webview.html, Binding JavaScript code to Android) and make a call from your javascript to:
public void myCallback(){ view.SetVisibilitu(View.VISIBLE) };
after the animations have ended?
I have a C# ASP.NET app that creates a JavaScript array of values for some user profile information. Client-side, I use jQuery/JavaScript to read the array and generate a mailto link. Some of the fields can contain special characters, such as ' & = / \ ".
Here's the C# code:
private String generateElementsArray(){
StringBuilder sb = new StringBuilder();
sb.Append("var currentElements = { currentUserName: '");
sb.Append(currentUserName);
sb.Append("', currentUserEmail: '");
sb.Append(currentUserEmail);
sb.Append("', currentSite: '");
sb.Append(currentSite);
sb.Append("', currentTitle: '");
sb.Append(currentTitle);
sb.Append("'}");
return sb.ToString();
}
I write the value of the above method to the page, which produces this JavaScript:
<script type="text/javascript">var currentElements = { currentUserName: 'Alex', currentUserEmail: 'myemailID', currentSite: 'Helpdesk', currentTitle: 'Phone User Guides & Troubleshooting'}</script>
Then I generate the email link using this JavaScript code, attaching the anchor tag to an element on the page:
function generateEmailTo(){
var body = currentElements.currentUserName + ' has shared a page with you on the intranet.%0A%0APage Title: %22' +
currentElements.currentTitle.replace("&","and") + '%22%0A' + $(location).attr('href').replace('#','');
var subject = currentElements.currentUserName + ' has shared a page with you on the intranet';
var mailto = 'mailto: ?body=' + body + '&subject=' + subject;
var anchor = '';
$("#email-placeholder").wrap(anchor);
}
....
<img id="email-placeholder" title="Send this page to a friend." src="<%= baseUrl %>/SiteAssets/media/icons/email-icon.gif"/>
For the mailto body text, I've noticed that it only takes a small set of the encoded characters, such as %22 for double-quotes, and %0A for line breaks. How do I pass the special characters such as single quotes, ampersands, etc., to the mailto body text and keep JavaScript happy?
Mailto is a URI scheme so all of its components must be URI encoded. You can use JavaScript encodeURIComponent function to encode mailto components. Please see the following example:
function buildMailTo(address, subject, body) {
var strMail = 'mailto:' + encodeURIComponent(address)
+ '?subject=' + encodeURIComponent(subject)
+ '&body=' + encodeURIComponent(body);
return strMail;
}
var strTest = buildMailTo('abc#xyz.com', 'Foo&foo', 'Bar\nBar');
/* strTest should be "mailto:abc%40xyz.com?subject=Foo%26foo&body=Bar%0ABar" */
window.open(strTest);
Hope this help.