Tuesday, September 27, 2016

Are all html element closed? Testing it with Javascript

This small snippet check if all html tags are properly closed.

The html can be passed as a string or as an array containing html strings. It is based on the work of Jonathan Aquino that has an online form that has a similar script implemented: http://jona.ca/blog/unclosed-tag-finder

The script run both in NodeJS and in the browser console. I added also a function that allow to test the html coming from a server using the URL.

The usage is:

凸.checkHtml("your html here")

or

凸.checkHtml(["your html here", "and here"])

If you want to check a page served by a server:

凸.buildGetPageFunction()('http://example.com', function(data){console.log(凸.checkHtml(data))})

These commands are available in the console after you copy and paste the snipped there.

The code can run also server side with

$ node closed-tag-testing.js

Be aware that in the console you can only check pages that belong to the same domain where you are in. If you try

凸.buildGetPageFunction()('http://google.com', function(data){console.log(凸.checkHtml(data))})

While being in http://example.com you will get the error:

XMLHttpRequest cannot load http://google.com/. It has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access.


// See https://coding-and-design.blogspot.de/2016/11/are-all-element-tags-closed-testing-it.html for more info
var 凸 = typeof global === 'undefined' ? 凸 : global.tmp;
var 凸 = (function (凸) {
凸.buildGetPageFunction = function buildGetPageFunction() {
if (typeof global === 'undefined') {
// Browser
return function (url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
return callback(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
};
} else {
// Node
return function (url, callback) {
var request = require("request");
request({ url: url }, function (err, response, responseText) {
if (!err && response.statusCode === 200) {
return callback(responseText);
} else {
throw err;
}
});
};
}
};
return 凸;
}(凸 || {}));
var 凸 = (function (凸) {
function isSelfClosingTag(tagName) {
return tagName.match(/area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr|script/i);
}
function displayLine(line, array) {
return ('Line #' + line + ': ' + array[line - 1]);
}
凸.checkHtml = function checkHtml(p) {
// Based on http://jona.ca/blog/unclosed-tag-finder
var
array1 = p.constructor === Array ? p : p.split('\n'),
tags = [],
tag,
openTags = [],
openTag,
i,
j,
line,
array2,
matches,
closingTag;
for (i = 0; i < array1.length; i++) {
line = array1[i];
array2 = line.match(/<[^>]*[^/]>/g) || [];
for (j = 0; j < array2.length; j++) {
tag = array2[j];
matches = tag.match(/<\/?([a-z0-9]+)/i);
if (matches) {
tags.push({ tag: tag, name: matches[1], line: i + 1, closing: tag[1] === '/' });
}
}
}
if (tags.length === 0) {
return 'No tags found.';
}
for (i = 0; i < tags.length; i++) {
tag = tags[i];
if (tag.closing) {
closingTag = tag;
if (isSelfClosingTag(closingTag.name)) {
continue;
}
if (openTags.length === 0) {
return [
'Closing tag ' + closingTag.tag + ' on line ' + closingTag.line + ' does not have corresponding open tag.',
displayLine(closingTag.line, array1),
].join('\n');
}
openTag = openTags[openTags.length - 1];
if (closingTag.name !== openTag.name) {
return [
'Closing tag ' + closingTag.tag + ' on line ' + closingTag.line + ' does not match open tag ' + openTag.tag + ' on line ' + openTag.line + '.',
displayLine(openTag.line, array1),
displayLine(closingTag.line, array1)
].join('\n');
} else {
openTags.pop();
}
} else {
openTag = tag;
if (isSelfClosingTag(openTag.name)) {
continue;
}
openTags.push(openTag);
}
}
if (openTags.length > 0) {
openTag = openTags[openTags.length - 1];
return [
'Open tag ' + openTag.tag + ' on line ' + openTag.line + ' does not have a corresponding closing tag.',
displayLine(openTag.line, array1),
].join('\n');
}
return 'Success: No unclosed tags found.';
};
return 凸;
}(凸 || {}));
(function () {
var url = (typeof global === 'undefined') ? document.location.href : "http://example.com";
凸.buildGetPageFunction()(url, function (page) {
console.log("### Checking " + url + "\n\n" + 凸.checkHtml(page) + "\n\n");
});
console.log("### Checking <div>\n\n" + 凸.checkHtml("<div>") + "\n\n");
console.log("### Checking ['<div>']\n\n" + 凸.checkHtml(["<div>"]) + "\n\n");
})();

No comments :

Post a Comment