Skip to content

Commit

Permalink
handle empty class attributes (#922)
Browse files Browse the repository at this point in the history
fixes #921
  • Loading branch information
alexlamsl authored May 20, 2018
1 parent a5cb4ea commit 9ecabca
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 21 deletions.
45 changes: 24 additions & 21 deletions src/htmlminifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ var UglifyJS = require('uglify-js');
var utils = require('./utils');

function trimWhitespace(str) {
if (typeof str !== 'string') {
return str;
}
return str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
return str && str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
}

function collapseWhitespaceAll(str) {
Expand Down Expand Up @@ -258,7 +255,7 @@ function isSrcset(attrName, tag) {
}

function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
if (attrValue && isEventAttribute(attrName, options)) {
if (isEventAttribute(attrName, options)) {
attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '');
return options.minifyJS(attrValue, true);
}
Expand Down Expand Up @@ -314,7 +311,7 @@ function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
return (+numString).toString();
});
}
else if (attrValue && options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {
else if (options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {
attrValue = attrValue.replace(/\n+|\r+|\s{2,}/g, '');
}
else if (tag === 'script' && attrName === 'type') {
Expand Down Expand Up @@ -522,7 +519,7 @@ function canTrimWhitespace(tag) {
}

function normalizeAttr(attr, attrs, tag, options) {
var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
var attrName = options.name(attr.name),
attrValue = attr.value;

if (options.decodeEntities && attrValue) {
Expand All @@ -538,7 +535,9 @@ function normalizeAttr(attr, attrs, tag, options) {
return;
}

attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
if (attrValue) {
attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
}

if (options.removeEmptyAttributes &&
canDeleteEmptyAttribute(tag, attrName, attrValue, options)) {
Expand Down Expand Up @@ -615,6 +614,9 @@ function identity(value) {

function processOptions(values) {
var options = {
name: function(name) {
return name.toLowerCase();
},
canCollapseWhitespace: canCollapseWhitespace,
canTrimWhitespace: canTrimWhitespace,
html5: true,
Expand All @@ -631,7 +633,12 @@ function processOptions(values) {
};
Object.keys(values).forEach(function(key) {
var value = values[key];
if (key === 'log') {
if (key === 'caseSensitive') {
if (value) {
options.name = identity;
}
}
else if (key === 'log') {
if (typeof value === 'function') {
options.log = value;
}
Expand Down Expand Up @@ -732,7 +739,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {

function attrNames(attrs) {
return attrs.map(function(attr) {
return options.caseSensitive ? attr.name : attr.name.toLowerCase();
return options.name(attr.name);
});
}

Expand All @@ -756,7 +763,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
}
for (var i = 0, len = attrs.length; i < len; i++) {
var attr = attrs[i];
if (classChain && (options.caseSensitive ? attr.name : attr.name.toLowerCase()) === 'class') {
if (classChain && attr.value && options.name(attr.name) === 'class') {
classChain.add(trimWhitespace(attr.value).split(/[ \t\n\f\r]+/).filter(shouldSkipUIDs));
}
else if (options.processScripts && attr.name.toLowerCase() === 'type') {
Expand Down Expand Up @@ -946,16 +953,13 @@ function minify(value, options, partialMarkup) {
html5: options.html5,

start: function(tag, attrs, unary, unarySlash, autoGenerated) {
var lowerTag = tag.toLowerCase();

if (lowerTag === 'svg') {
if (tag.toLowerCase() === 'svg') {
options = Object.create(options);
options.keepClosingSlash = true;
options.caseSensitive = true;
options.keepClosingSlash = true;
options.name = identity;
}

tag = options.caseSensitive ? tag : lowerTag;

tag = options.name(tag);
currentTag = tag;
charsPrevTag = tag;
if (!inlineTextTags(tag)) {
Expand Down Expand Up @@ -1035,11 +1039,10 @@ function minify(value, options, partialMarkup) {
}
},
end: function(tag, attrs, autoGenerated) {
var lowerTag = tag.toLowerCase();
if (lowerTag === 'svg') {
if (tag.toLowerCase() === 'svg') {
options = Object.getPrototypeOf(options);
}
tag = options.caseSensitive ? tag : lowerTag;
tag = options.name(tag);

// check if current tag is in a whitespace stack
if (options.collapseWhitespace) {
Expand Down
4 changes: 4 additions & 0 deletions tests/minifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -3229,6 +3229,10 @@ QUnit.test('sort style classes', function(assert) {
removeAttributeQuotes: true,
sortClassName: true
}), output);

input = '<div class></div>';
assert.equal(minify(input, { sortClassName: false }), input);
assert.equal(minify(input, { sortClassName: true }), input);
});

QUnit.test('decode entity characters', function(assert) {
Expand Down

0 comments on commit 9ecabca

Please sign in to comment.