improve interaction of keepClosingSlash & removeAttributeQuotes
authoralexlamsl <alexlamsl@gmail.com>
Tue, 19 Jan 2016 08:57:00 +0000 (16:57 +0800)
committeralexlamsl <alexlamsl@gmail.com>
Tue, 19 Jan 2016 08:57:00 +0000 (16:57 +0800)
src/htmlminifier.js
tests/minifier.js

index 639728f..e91b37e 100644 (file)
     return (/^on[a-z]+/).test(attrName);
   }
 
-  function canRemoveAttributeQuotes(value, isLast) {
+  function canRemoveAttributeQuotes(value) {
     // http://mathiasbynens.be/notes/unquoted-attribute-values
-    return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value) &&
-           // make sure trailing slash is not interpreted as HTML self-closing tag
-           !(isLast && (/\/$/).test(value));
+    return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value);
   }
 
   function attributesInclude(attributes, attribute) {
     return !(/^(?:pre|textarea)$/.test(tag));
   }
 
-  function normalizeAttribute(attr, attrs, tag, unarySlash, index, options, isLast) {
+  function normalizeAttribute(attr, attrs, tag, hasUnarySlash, index, options, isLast) {
 
     var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
         attrValue = options.preventAttributesEscaping ? attr.value : attr.escaped,
         attrQuote = options.preventAttributesEscaping ? attr.quote : (options.quoteCharacter === '\'' ? '\'' : '"'),
         attrFragment,
-        emittedAttrValue,
-        isTerminalOfUnarySlash = unarySlash && index === attrs.length - 1;
+        emittedAttrValue;
 
     if ((options.removeRedundantAttributes &&
       isAttributeRedundant(tag, attrName, attrValue, attrs))
     attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
 
     if (attrValue !== undefined && !options.removeAttributeQuotes ||
-        !canRemoveAttributeQuotes(attrValue, isLast) || isTerminalOfUnarySlash) {
+        !canRemoveAttributeQuotes(attrValue)) {
       emittedAttrValue = attrQuote + attrValue + attrQuote;
     }
+    // make sure trailing slash is not interpreted as HTML self-closing tag
+    else if (isLast && (hasUnarySlash || /\/$/.test(attrValue))) {
+      emittedAttrValue = attrValue + ' ';
+    }
     else {
       emittedAttrValue = attrValue;
     }
         }
 
         var openTag = '<' + tag;
-        var closeTag = ((unarySlash && options.keepClosingSlash) ? '/' : '') + '>';
+        var hasUnarySlash = unarySlash && options.keepClosingSlash;
+        var closeTag = (hasUnarySlash ? '/' : '') + '>';
         if (attrs.length === 0) {
           openTag += closeTag;
         }
           if (lint) {
             lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].escaped);
           }
-          token = normalizeAttribute(attrs[i], attrs, tag, unarySlash, i, options, isLast);
+          token = normalizeAttribute(attrs[i], attrs, tag, hasUnarySlash, i, options, isLast);
           if (isLast) {
             token += closeTag;
           }
index d5af244..b9ce4a2 100644 (file)
     equal(minify(input, { removeAttributeQuotes: true }), '<a href=http://example.com/ title=blah>\nfoo\n\n</a>');
 
     input = '<a title="blah" href="http://example.com/">\nfoo\n\n</a>';
-    equal(minify(input, { removeAttributeQuotes: true }), '<a title=blah href="http://example.com/">\nfoo\n\n</a>');
+    equal(minify(input, { removeAttributeQuotes: true }), '<a title=blah href=http://example.com/ >\nfoo\n\n</a>');
 
     input = '<p class=foo|bar:baz></p>';
     equal(minify(input, { removeAttributeQuotes: true }), '<p class=foo|bar:baz></p>');
   test('keeping trailing slashes in tags', function() {
     equal(minify('<img src="test"/>', { keepClosingSlash: true }), '<img src="test"/>');
     // https://github.com/kangax/html-minifier/issues/233
-    equal(minify('<img src="test"/>', { keepClosingSlash: true, removeAttributeQuotes: true }), '<img src="test"/>');
-    equal(minify('<img title="foo" src="test"/>', { keepClosingSlash: true, removeAttributeQuotes: true }), '<img title=foo src="test"/>');
+    equal(minify('<img src="test"/>', { keepClosingSlash: true, removeAttributeQuotes: true }), '<img src=test />');
+    equal(minify('<img title="foo" src="test"/>', { keepClosingSlash: true, removeAttributeQuotes: true }), '<img title=foo src=test />');
   });
 
   test('removing optional tags', function() {