Start testing HTMLLint. Add detection of href="javascript:void(0)" during linting.
authorJuriy Zaytsev <kangax@gmail.com>
Wed, 10 Mar 2010 17:37:04 +0000 (12:37 -0500)
committerJuriy Zaytsev <kangax@gmail.com>
Wed, 10 Mar 2010 17:37:04 +0000 (12:37 -0500)
index.html
master.css
src/htmllint.js
src/htmlminifier.js
tests/lint-tests.html [new file with mode: 0644]

index 87558b8..76f8fe8 100644 (file)
           <li>HTMLLint: warn about repeating attributes (e.g. multiple styles, classes, etc.)</li>
           <li>HTMLLint: warn about repeating &amp;nbsp; or &lt;br> sequences</li>
           <li>HTMLLint: warn about missing doctype</li>
-          <li>HTMLLint: warn about <code>href="javascript:void 0"</code></li>
         </ul>
       </div>
       <p class="quiet" style="font-style:italic;">
index e7e6ee1..b8705c1 100644 (file)
@@ -26,4 +26,4 @@ button { font-weight: bold; width: 100px; }
 .short { display: inline-block; width: 20em; margin-top: 0.25em; }
 
 .deprecated-element, .deprecated-attribute { color: red; }
-.presentational-element, .presentational-attribute { color: #FF8C00; }
\ No newline at end of file
+.presentational-element, .presentational-attribute, .inaccessible-attribute { color: #FF8C00; }
\ No newline at end of file
index 3de3225..53b6dea 100644 (file)
       (attrName === 'width' && (/^(?:hr|td|th|applet|pre)$/).test(tag))
     );
   }
+  function isInaccessibleAttribute(attrName, attrValue) {
+    return (
+      attrName === 'href' && 
+      (/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i).test(attrValue)
+    );
+  }
   
   function Lint() {
     this.log = [ ];
   }
   
-  Lint.prototype._testElement = function(tag, attrName) {
+  Lint.prototype.testElement = function(tag) {
     if (isDeprecatedElement(tag)) {
       this.log.push(
         '<li>Warning: found <span class="deprecated-element">deprecated element</span> (<strong>', 
@@ -74,7 +80,7 @@
     }
   };
   
-  Lint.prototype._testAttribute = function(tag, attrName) {
+  Lint.prototype.testAttribute = function(tag, attrName, attrValue) {
     if (isEventAttribute(attrName)) {
       this.log.push(
         '<li>Warning: found <span class="event-attribute">event attribute</span> (<strong>', 
     else if (isDeprecatedAttribute(tag, attrName)) {
       this.log.push(
         '<li>Warning: found <span class="deprecated-attribute">deprecated attribute</span> (<strong>', 
-        attrName, '</strong> on <code>', tag, '</code> element)</li>');
+        attrName, '</strong> on <code>&lt;', tag, '&gt;</code> element)</li>');
     }
     else if (isStyleAttribute(attrName)) {
       this.log.push(
-        '<li>Warning: found <span class="style-attribute">style attribute</span> (on <code>', tag, '</code> element)</li>');
+        '<li>Warning: found <span class="style-attribute">style attribute</span> (on <code>&lt;', tag, '&gt;</code> element)</li>');
+    }
+    else if (isInaccessibleAttribute(attrName, attrValue)) {
+      this.log.push(
+        '<li>Warning: found <span class="inaccessible-attribute">inaccessible attribute</span> '+
+          '(on <code>&lt;', tag, '&gt;</code> element)</li>');
     }
   };
   
-  Lint.prototype.test = function(tag, attrName) {
-    this._testElement(tag, attrName);
-    this._testAttribute(tag, attrName);
+  Lint.prototype.test = function(tag, attrName, attrValue) {
+    this.testElement(tag);
+    this.testAttribute(tag, attrName, attrValue);
   };
   
   Lint.prototype.populate = function(writeToElement) {
index dd7a9c9..2092add 100644 (file)
         
         buffer.push('<', tag);
         
+        lint && lint.testElement(tag);
+        
         for ( var i = 0, len = attrs.length; i < len; i++ ) {
-          lint && lint.test(tag, attrs[i].name.toLowerCase());
+          lint && lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].escaped);
           buffer.push(normalizeAttribute(attrs[i], attrs, tag, options));
         }
         
diff --git a/tests/lint-tests.html b/tests/lint-tests.html
new file mode 100644 (file)
index 0000000..d121159
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+  "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <title></title>
+    <link rel="stylesheet" href="qunit.css" type="text/css">
+    <script type="text/javascript" src="qunit.js"></script>
+    <script type="text/javascript" src="../src/htmlparser.js"></script>
+    <script type="text/javascript" src="../src/htmlminifier.js"></script>
+    <script type="text/javascript" src="../src/htmllint.js"></script>
+  </head>
+  <body>
+    
+    <h1 id="qunit-header">HTML Lint</h1>
+    <h2 id="qunit-banner"></h2>
+    <h2 id="qunit-userAgent"></h2>
+    <ol id="qunit-tests"></ol>
+    
+    <script type="text/javascript">
+      
+      (function(global){
+        
+        var minify = global.minify, input, output, lint;
+        
+        module('', {
+          setup: function() {
+            lint = new HTMLLint();
+          }
+        });
+        
+        test('lint exists', function() {
+          ok(typeof lint !== 'undefined');
+        });
+        
+        test('lint is instance of HTMLLint', function() {
+          ok(lint instanceof HTMLLint);
+        });
+        
+        test('lint API', function() {
+          equals(0, lint.log.length, '`log` property exists');
+          equals("function", typeof lint.populate, '`populate` method exists');
+          equals("function", typeof lint.test, '`test` method exists');
+          equals("function", typeof lint.testElement, '`testElement` method exists');
+          equals("function", typeof lint.testAttribute, '`testAttribute` method exists');
+        });
+        
+        test('deprecated element (font)', function(){
+          minify('<font>foo</font>', { lint: lint });
+          var log = lint.log.join('');
+          
+          ok(log.indexOf('font') > -1);
+          ok(log.indexOf('deprecated element') > -1);
+        });
+        
+      })(this);
+    </script>
+  </body>
+</html>
\ No newline at end of file