I am trying to automate this webpage inside of Android. So far I got my webview to successfully fill out the form, but the only problem is the final button click at the bottom of the page. Here is my code:
// Fill out form
webview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
WebView myWebView = (WebView) findViewById(R.id.webview);
//hide loading image
findViewById(R.id.progressBar).setVisibility(View.GONE);
//show WebView
findViewById(R.id.webview).setVisibility(View.VISIBLE);
myWebView.loadUrl("javascript:document.getElementById('join_first_name').value='" + name + "';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('join_last_name').value='" + lastName + "';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('join_email').value='" + email + "';void(0);");
myWebView.loadUrl("javascript:document.getElementById('join_confirm_email').value='" + email + "';void(0);");
myWebView.loadUrl("javascript:document.getElementById('join_password').value='" + password + "';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('join_confirm_password').value='" + password + "';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('phone_number_a').value='231';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('phone_number_b').value='123';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('phone_number_c').value='2310';void(0); ");
myWebView.loadUrl("javascript:document.getElementById('join_i_agree').click();void(0); ");
myWebView.loadUrl("javascript:document.getElementById('join_card_not_available').click();void(0); ");
myWebView.loadUrl("javascript:document.getElementById('#join-now-primary')[1];void(0); ");
myWebView.pageDown(true);
// Make sure a toast is only shown once.
while (toastCheck) {
Toast.makeText(MainActivity.this, "Click the \"join\" button.", Toast.LENGTH_SHORT).show();
toastCheck = false;
}
}
});
My Question is: How can I click the button at the bottom of the page?
HTML 4.01 specification says ID must be document-wide unique.
HTML 5 specification says the same thing but in other words. It says that ID must be unique in its home subtree, which is basically the document if we read the definition of it.
Source: https://softwareengineering.stackexchange.com/questions/127178/two-html-elements-with-same-id-attribute-how-bad-is-it-really
You should contact with website developer I guess. Also you can trigger it like this:
javascript:document.getElementById('join-now-primary').click();
Edit:
That website is using jQuery, so you can use jquery functions, please try again like this:
String injection = "javascript:"
injection += "$('#join_first_name').val('"+lastName+"');"
injection += "$('#join_email').val('"+email+"');"
injection += "$('#join_confirm_email').val('"+email+"');"
injection += "$('#join_password').val('"+password+"');"
injection += "$('#join_confirm_password').val('"+password+"');"
injection += "$('#phone_number_a').val('2122');"
injection += "$('#phone_number_b').val('122');"
injection += "$('#phone_number_c').val('122');"
injection += "$('#join_i_agree').trigger('click');"
injection += "$('#join_card_not_available').trigger('click');"
/* trigger form*/
injection += "var formElement = $('#join_now_form');"
injection += "formHandler = new FormHandler('#join_now_form', {disableDefaultSubmision: true});"
injection += "formHandler.clearError();"
injection += "formHandler.init();"
injection += "formHandler.submitHandler = function(){ formElement.trigger('submitHandler', [formHandler]);}"
injection += "AccountModals.init(formHandler, 'registration');"
webView.loadUrl(injection)
Related
I'm building an app that uses a webview. It loads mobile version of a website. But my client wanted me to change and delete some text.
I did it with javascript but after i did this, some sliders stopped working anymore. Without javascript it works perfect. But i have to change and remove texts somehow.
my webview settings;
wSettings=webView.getSettings();
wSettings.setJavaScriptEnabled(true);
wSettings.setDomStorageEnabled(true);
webView.loadUrl("http://www.evdusum.com");
and the javascript that i used in onPageFinished;
#Override
public void onPageFinished(WebView view, String url) {
String link1 = "SİTEDE ARAYIN";
String link2 = "ARA";
String a="Bu sitede kullanılan yazılı ya da görsel dokümanlar izinsiz kullanılamaz.";
String b=" ";
view.loadUrl("javascript:(function(){document.body.innerHTML = document.body.innerHTML.replace('" + link1+"', '" + link2+"')})()");
view.loadUrl("javascript:(function(){document.body.innerHTML = document.body.innerHTML.replace('" + a+"', '" + b+"')})()");
((RelativeLayout)findViewById(R.id.start)).setVisibility(View.GONE);
}
Until Android api 18 (JELLY_BEAN_MR1) you can use this view.loadUrl("javascript:");. Just use ONE call to insert and call your js. If you need to perfome long code, build a function and call it at the "same call" of webView.loadUrl().
Some example:
webView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
"script.innerHTML = function your_function(var1, var2){document.body.innerHTML = document.body.innerHTML.replace(var1, var2); return true;}" +
"parent.appendChild(script);" +
"your_function('"+link1+"','"+link2+"')" + ";})();");
Android api >=19 use webView.evaluateJavascript. Here some example:
webView.evaluateJavascript("(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
"script.innerHTML = function your_function(var1, var2){document.body.innerHTML = document.body.innerHTML.replace(var1, var2); return true;}" +
"parent.appendChild(script);" +
"return your_function('"+link1+"','"+link2+"');})();", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
Log.v("TAG", "Response from JS"+value)
}
});
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 find or make a bookmarklet that will validate the html content of a currently viewed page using the W3C HTML 5 validator.
I have found two bookmarklets and am trying to get one to behave a bit like one and a bit like the other, however I am not sure how to do this.
Chris Coyier has an HTML5 validation bookmarklet that works well except it uses the page URI so does not work for locally tested sites:
javascript:(function(){%20function%20fixFileUrl(u)%20{%20var%20windows,u;%20windows%20=%20(navigator.platform.indexOf("Win")%20!=%20-1);%20%20/*%20chop%20off%20file:///,%20unescape%20each%20%hh,%20convert%20/%20to%20\%20and%20|%20to%20:%20*/%20%20u%20=%20u.substr(windows%20?%208%20:%207);%20u%20=%20unescape(u);%20if(windows)%20{%20u%20=%20u.replace(/\//g,"\");%20u%20=%20u.replace(/\|/g,":");%20}%20return%20u;%20}%20/*%20bookmarklet%20body%20*/%20var%20loc,fileloc;%20loc%20=%20document.location.href;%20if%20(loc.length%20>%209%20&&%20loc.substr(0,8)=="file:///")%20{%20fileloc%20=%20fixFileUrl(loc);%20if%20(prompt("Copy%20filename%20to%20clipboard,%20press%20enter,%20paste%20into%20validator%20form",%20fileloc)%20!=%20null)%20{%20document.location.href%20=%20"http://validator.w3.org/file-upload.html"%20}%20}%20else%20document.location.href%20=%20"http://validator.w3.org/check?uri="%20+%20escape(document.location.href);%20void(0);%20})();
I also found this one, which works by grabbing the html of the current page, but I can't figure out how to make it do html5... there is reference to doctype in the code and I have tried changing this to html5, html500 etc, and removing it entirely hoping it would autodetect.. but to no avail:
javascript:(function(){var h=document;var b=h.doctype;var e="<!DOCTYPE "+b.name.toLowerCase()+' PUBLIC "'+b.publicId+'" "'+b.systemId+'">\n';var g=h.documentElement.outerHTML;var f="http://validator.w3.org/check";var i={prefill_doctype:"html401",prefill:0,doctype:"inline",group:0,ss:1,st:1,outline:1,verbose:1,fragment:e+g};var a=h.createElement("form");a.setAttribute("method","post");a.setAttribute("target","_blank");a.setAttribute("action",f);for(var j in i){var c=h.createElement("input");c.setAttribute("type","hidden");c.setAttribute("name",j);c.setAttribute("value",i[j]);a.appendChild(c)}if(navigator.appCodeName=="Mozilla"){h.body.appendChild(a)}a.submit()})();
First, you need an exact copy of the HTML document (including Doctype etc). For this purpose, I have written the following function:
function DOMtoString(document_root) {
var html = '',
node = document_root.firstChild;
while (node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
html += node.outerHTML;
break;
case Node.TEXT_NODE:
html += node.nodeValue;
break;
case Node.CDATA_SECTION_NODE:
html += '<![CDATA[' + node.nodeValue + ']]>';
break;
case Node.COMMENT_NODE:
html += '<!--' + node.nodeValue + '-->';
break;
case Node.DOCUMENT_TYPE_NODE:
// (X)HTML documents are identified by public identifiers
html += "<!DOCTYPE "
+ node.name
+ (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '')
+ (!node.publicId && node.systemId ? ' SYSTEM' : '')
+ (node.systemId ? ' "' + node.systemId + '"' : '')
+ '>\n';
break;
}
node = node.nextSibling;
}
return html;
}
Then, a form has to be created and submitted. After inspecting the form submission to http://validator.w3.org/check, I've created the following function, which submits the significant key-value pairs:
javascript:(function() {
var html_to_validate = DOMtoString(document);
/* Paste the DOMtoString function here */
function append(key, value) {
var input = document.createElement('textarea');
input.name = key;
input.value = value;
form.appendChild(input);
}
var form = document.createElement('form');
form.method = 'POST';
form.action = 'http://validator.w3.org/check';
form.enctype = 'multipart/form-data'; // Required for this validator
form.target = '_blank'; // Open in new tab
append('fragment', html_to_validate); // <-- Code to validate
append('doctype', 'HTML5'); // Validate as HTML 5
append('group', '0');
document.body.appendChild(form);
form.submit();
})();
Bookmarklet
Copy the previous two blocks to Google's closure compiler. Do not forget to prefix javascript: again.
javascript:(function(){function c(a,b){var c=document.createElement("textarea");c.name=a;c.value=b;d.appendChild(c)}var e=function(a){for(var b="",a=a.firstChild;a;){switch(a.nodeType){case Node.ELEMENT_NODE:b+=a.outerHTML;break;case Node.TEXT_NODE:b+=a.nodeValue;break;case Node.CDATA_SECTION_NODE:b+="<![CDATA["+a.nodeValue+"]]\>";break;case Node.COMMENT_NODE:b+="<\!--"+a.nodeValue+"--\>";break;case Node.DOCUMENT_TYPE_NODE:b+="<!DOCTYPE "+a.name+(a.publicId?' PUBLIC "'+a.publicId+'"':"")+(!a.publicId&&a.systemId? " SYSTEM":"")+(a.systemId?' "'+a.systemId+'"':"")+">\n"}a=a.nextSibling}return b}(document),d=document.createElement("form");d.method="POST";d.action="http://validator.w3.org/check";d.enctype="multipart/form-data";d.target="_blank";c("fragment",e);c("doctype","HTML5");c("group","0");document.body.appendChild(d);d.submit()})();
I was also getting the 'Sorry! This document cannot be checked.' error, resolved it by adding an accept-charset "utf-8" to the form attributes.
In the function that creates the form element add the following line: form.acceptCharset = "utf-8";
It worked for me.
Marta's answer helped me out. Here is the updated bookmarklet.
javascript:(function(){function c(a,b){var c=document.createElement("textarea");c.name=a;c.value=b;d.appendChild(c)}var e=function(a){for(var b="",a=a.firstChild;a;){switch(a.nodeType){case Node.ELEMENT_NODE:b+=a.outerHTML;break;case Node.TEXT_NODE:b+=a.nodeValue;break;case Node.CDATA_SECTION_NODE:b+="<![CDATA["+a.nodeValue+"]]\>";break;case Node.COMMENT_NODE:b+="<\!--"+a.nodeValue+"--\>";break;case Node.DOCUMENT_TYPE_NODE:b+="<!DOCTYPE "+a.name+(a.publicId?' PUBLIC "'+a.publicId+'"':"")+(!a.publicId&&a.systemId? " SYSTEM":"")+(a.systemId?' "'+a.systemId+'"':"")+">\n"}a=a.nextSibling}return b}(document),d=document.createElement("form");d.method="POST";d.action="http://validator.w3.org/check";d.enctype="multipart/form-data";d.target="_blank";d.acceptCharset="utf-8";c("fragment",e);c("doctype","HTML5");c("group","0");document.body.appendChild(d);d.submit()})();
The previous answers didn't work form me. I'm using the "Check serialized DOM of Current Page" bookmarklet at https://validator.w3.org/nu/about.html. This seems to work wonderfully, picking up dynamically generated HTML.
I am working on a mvc3 application and I need to modify the style of the ValidatioSummary message, to do so, I created my own HTM helper which is as follows:
public static MvcHtmlString MyValidationSummary(this HtmlHelper helper){
string retainHtml +="";
int counterror = 0;
if (helper.ViewData.ModelState..IsValid)
{
TagBuilder tag = new TagBuilder("div");
tag.Attributes.Add("class", "validation-summary-valid");
tag.Attributes.Add("data-valmsg-summary", "true");
tag.InnerHtml += "<span> There was" + countererror + "errors found<ul><li></li></ul>"
retainHtml += tag.ToString();
return MvcHtmlString.Create(retainHtml);
}
if (!helper.ViewData.ModelState.IsValid)
{
TagBuilder tag = new TagBuilder("div");
tag.Attributes.Add("class", "validation-summary-errors");
tag.Attributes.Add("data-valmsg-summary", "true");
retainHtml +="<div class='validation-summary-errors'><span>";
counterror = 1;
string temretainhtml ="";
foreach (var key in helper.ViewData.ModelState.keys)
}
foreach (var err in helper.ViewData.ModelState[key].Errors)
temretainhtml += "<li>Error " + countererror++ + " : " + err.ErrorMessage + "</li>";
}
retainHtml += "Error ! there was " + --countererror + " errors found";
retainHtml += "</span>";
retainHtml += "<ul>";
retainHtml += temretainhtml;
retainHtml += "</ul></div>";
}
return MvcHtmlString.Create(retainHtml);
}
}
}
This works perfect with server side validation, but I need to implement this style on the Client side validation as well, right now, the forms are displaying the validationSummary on the top of the page on client side but with the default MVC format, not the one I specified in my HTML helper, I've been doing a lot of research but unfortunately I haven't had any luck, may I need to do any change in the jquery.validate.unobtrusive.js file to apply these changes? or do I need to create another validation file in jquery? My experience in jquery is very poor and I am very lost right now, any help you can give me please it'll be really appreciated.
Many thanks!!!
Late answer:
The jquery.validate.unobtrusive.js is hard to hook in to. Instead of modifying the file (never ideal) try this:
Listen to the following event
form.bind("invalid-form.validate", handler...
And then then build your own summary:
form.bind("invalid-form.validate", function (evt, validator) {
var container = $(this).find("[data-valmsg-summary=true]");
var list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li style='color:#00aa00'/>").html(this.message).appendTo(list);
});
}
});
You should have a look at the end of this tutorial:
http://thepursuitofalife.com/asp-net-mvc-3-unobtrusive-javascript-validation-with-custom-validators/
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.