draggable is enumerated attribute, `auto` default
authorDuncan Beevers <duncan@dweebd.com>
Tue, 2 Sep 2014 03:15:09 +0000 (22:15 -0500)
committerDuncan Beevers <duncan@dweebd.com>
Tue, 2 Sep 2014 11:27:23 +0000 (06:27 -0500)
src/htmlminifier.js
tests/minifier.js

index 52254f7..8541579 100644 (file)
     );
   }
 
-  function isBooleanAttribute(attrName) {
-    return (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i).test(attrName);
+  var enumeratedAttributeValues = {
+    draggable: ['true', 'false'] // defaults to 'auto'
+  };
+
+  function isBooleanAttribute(attrName, attrValue) {
+    var isSimpleBoolean = (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i).test(attrName);
+    if (isSimpleBoolean) {
+      return true;
+    }
+
+    var attrValueEnumeration = enumeratedAttributeValues[attrName.toLowerCase()];
+    if (!attrValueEnumeration) {
+      return false;
+    }
+    else {
+      return (-1 === attrValueEnumeration.indexOf(attrValue.toLowerCase()));
+    }
   }
 
   function isUriTypeAttribute(attrName, tag) {
       '?:down|up|over|move|out)|key(?:press|down|up)))$');
 
   function canDeleteEmptyAttribute(tag, attrName, attrValue) {
-    var isValueEmpty = !attrValue || /^(["'])?\s*\1$/.test(attrValue);
+    var isValueEmpty = !attrValue || (/^\s*$/).test(attrValue);
     if (isValueEmpty) {
       return (
         (tag === 'input' && attrName === 'value') ||
     var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
         attrValue = attr.escaped,
         attrFragment,
+        emittedAttrValue,
         isTerminalOfUnarySlash = unarySlash && index === attrs.length - 1;
 
     if ((options.removeRedundantAttributes &&
 
     if (attrValue !== undefined && !options.removeAttributeQuotes ||
         !canRemoveAttributeQuotes(attrValue) || isTerminalOfUnarySlash) {
-      attrValue = '"' + attrValue + '"';
+      emittedAttrValue = '"' + attrValue + '"';
+    }
+    else {
+      emittedAttrValue = attrValue;
     }
 
     if (options.removeEmptyAttributes &&
     }
 
     if (attrValue === undefined || (options.collapseBooleanAttributes &&
-        isBooleanAttribute(attrName))) {
+        isBooleanAttribute(attrName, attrValue))) {
       attrFragment = attrName;
     }
     else {
-      attrFragment = attrName + attr.customAssign + attrValue;
+      attrFragment = attrName + attr.customAssign + emittedAttrValue;
     }
 
     return (' ' + attr.customOpen + attrFragment + attr.customClose);
index ccb28df..88baf94 100644 (file)
     equal(minify(input, { collapseBooleanAttributes: true, caseSensitive: true }), output);
   });
 
+  test('collapsing enumerated attributes', function() {
+    equal(minify('<div draggable="auto"></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div draggable="true"></div>', { collapseBooleanAttributes: true }), '<div draggable="true"></div>');
+    equal(minify('<div draggable="false"></div>', { collapseBooleanAttributes: true }), '<div draggable="false"></div>');
+    equal(minify('<div draggable="foo"></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div draggable></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div Draggable="auto"></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div Draggable="true"></div>', { collapseBooleanAttributes: true }), '<div draggable="true"></div>');
+    equal(minify('<div Draggable="false"></div>', { collapseBooleanAttributes: true }), '<div draggable="false"></div>');
+    equal(minify('<div Draggable="foo"></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div Draggable></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+    equal(minify('<div draggable="Auto"></div>', { collapseBooleanAttributes: true }), '<div draggable></div>');
+  });
+
   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