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.
Related
I am trying to pass arguments to onclick event of dynamically generated element. I have already seen the existing stackoveflow questions but it didn't answer my specific need.In this existing question , they are trying to access data using $(this).text(); but I can't use this in my example.
Click event doesn't work on dynamically generated elements
In below code snippet, I am trying to pass program and macroVal to onclick event but it doesn't work.
onClickTest = function(text, type) {
if(text != ""){
// The HTML that will be returned
var program = this.buffer.program;
var out = "<span class=\"";
out += type + " consolas-text";
if (type === "macro" && program) {
var macroVal = text.substring(1, text.length-1);
out += " macro1 program='" + program + "' macroVal='" + macroVal + "'";
}
out += "\">";
out += text;
out += "</span>";
console.log("out " + out);
$("p").on("click" , "span.macro1" , function(e)
{
BqlUtil.myFunction(program, macroVal);
});
}else{
var out = text;
}
return out;
};
console.log of out give me this
<span class="macro consolas-text macro1 program='test1' macroVal='test2'">{TEST}</span>
I have tried both this.program and program but it doesn't work.
Obtain values of span element attributes, since you include them in html:
$("p").on("click" , "span.macro" , function(e)
{
BqlUtil.myFunction(this.getAttribute("program"),
this.getAttribute("macroVal"));
});
There are, however, several things wrong in your code.
you specify class attribute twice in html assigned to out,
single quotes you use are not correct (use ', not ’),
quotes of attribute values are messed up: consistently use either single or double quotes for attribute values
var out = "<span class='";
...
out += "' class='macro' program='" + program + "' macroVal='" + macroVal + ;
...
out += "'>";
depending on how many times you plan to call onClickTest, you may end up with multiple click event handlers for p span.macro.
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)
I would like to have a code that can search through a website's html and find a certain item, then print that item. In my code, I use a file called getPageSource.js, to get the html, and if I wanted, I could print out the whole html. Let me post that here:
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;
}
chrome.runtime.sendMessage({
action: "getSource",
source: DOMtoString(document)
});
This code can allow me to open a website, and click on my extension, and my extension will open a page that will print out the HTML code. One issue solved. Now the main question is that I want my code to search through that HTML code and print out ONLY a certain item. Say I want it to print out the ID of a textbox on the page.
Let's use the Facebook login page as an example:
SO the WHOLE HTML code gets printed out, and this part is the main focus:
<input id= "email" class= "inputtext" type="email" tabindex="1" value= "" name="email" ></input>
This is one of the lines of code from the facebook.com login page. This line is specifically the code of the Email or Phone textbox. See how it says, id= "email" ? That is the part I would like my extension to print out only. SO when I click it, it just says "email" and under that the id of the one for the password box.
This is still for the same project of the extension signing in for me, and I would like to add this as a little feature, so that hopefully it can sign in to more websites for me.
Thank you very much in advance.
I know it's already discussed here, but there were no solution to get the whole document (including doctype).
$(document).html(); returns null...
This will get you all the HTML:
document.documentElement.outerHTML
Unfortunately it does not return the doctype. But you can use document.doctype to get it and glue the two together.
You can do
new XMLSerializer().serializeToString(document);
for all browsers newer than IE 9
try this.
$("html").html()
document is a variable it dose not represent the html tag.
EDIT
To get the doctype one could use
document.doctype
This is a function which has support in IE6+, it does't use outerHTML for even more support, it adds the doctype and uses a few tricks to get the html tag and its attributes. In order to receive a string with the doctype, and doesn't use outerHTML so it supports every browser. It uses a few tricks to get the html tag. Add this code:
document.fullHTML = function () {
var r = document.documentElement.innerHTML, t = document.documentElement.attributes, i = 0, l = '',
d = '<!DOCTYPE ' + document.doctype.name + (document.doctype.publicId ? ' PUBLIC "' + document.doctype.publicId + '"' : '') + (!document.doctype.publicId && document.doctype.systemId ? ' SYSTEM' : '') + (document.doctype.systemId ? ' "' + document.doctype.systemId + '"' : '') + '>';
for (; i < t.length; i += 1) l += ' ' + t[i].name + '="' + t[i].value + '"';
return d+'\n<html' + l + '>' + r + '</html>';
}
Now, you can run this function:
console.log(document.fullHTML());
This will return the HTML and doctype.
I ran this on example.com, here are the results
document.documentElement.innerHTML
will return you all document markup as string
to get the whole doctype read this
I'm not sure about getting the complete doc.but what you can do is,you can get the content of html tag seprately and doctype seprately.
$('html').html() for content and document.doctype for getting the doctype
I don't think there is a direct access to the whole document (including the doctype), but this works :
$.get(document.location, function(html) {
// use html (which is the complete source code, including the doctype)
});
I have done it on browser's console
document.documentElement;
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/