Special-case svg tags, preserve case and slashes
authorDuncan Beevers <duncan@dweebd.com>
Thu, 13 Nov 2014 15:14:34 +0000 (09:14 -0600)
committerDuncan Beevers <duncan@dweebd.com>
Thu, 11 Dec 2014 22:15:18 +0000 (16:15 -0600)
src/htmlminifier.js
tests/minifier.js

index 3516cf7..ae9e0ec 100644 (file)
   function minify(value, options) {
 
     options = options || {};
+    var optionsStack = [];
+
     value = trimWhitespace(value);
     setDefaultTesters(options);
 
       html5: typeof options.html5 !== 'undefined' ? options.html5 : true,
 
       start: function( tag, attrs, unary, unarySlash ) {
-
         if (isIgnoring) {
           buffer.push('<' + tag, attrsToMarkup(attrs), unarySlash ? '/' : '', '>');
           return;
         }
 
-        tag = options.caseSensitive ? tag : tag.toLowerCase();
+        var lowerTag = tag.toLowerCase();
+
+        if (lowerTag === 'svg') {
+          optionsStack.push(options);
+          var nextOptions = {};
+          for (var key in options) {
+            nextOptions[key] = options[key];
+          }
+          nextOptions.keepClosingSlash = true;
+          nextOptions.caseSensitive = true;
+          options = nextOptions;
+        }
+
+        tag = options.caseSensitive ? tag : lowerTag;
+
         currentTag = tag;
         currentChars = '';
         currentAttrs = attrs;
           return;
         }
 
+        var lowerTag = tag.toLowerCase();
+        if (lowerTag === 'svg') {
+          options = optionsStack.pop();
+        }
+
         // check if current tag is in a whitespace stack
         if (options.collapseWhitespace) {
           if (stackNoTrimWhitespace.length &&
         }
         else {
           // push end tag to buffer
-          buffer.push('</' + (options.caseSensitive ? tag : tag.toLowerCase()) + '>');
+          buffer.push('</' + (options.caseSensitive ? tag : lowerTag) + '>');
           results.push.apply(results, buffer);
         }
         // flush buffer
index ab9defe..b899c19 100644 (file)
   });
 
   test('caseSensitive', function() {
-    input = '<svg class="icon icon-activity-by-tag" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px" viewBox="0 0 100 100"><linearGradient><stop offset="0%"></stop><stop offset="50%"></stop></linearGradient></svg>';
+    input = '<div mixedCaseAttribute="value"></div>';
 
-    var caseSensitiveOutput = '<svg class="icon icon-activity-by-tag" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px" viewBox="0 0 100 100"><linearGradient><stop offset="0%"></stop><stop offset="50%"></stop></linearGradient></svg>';
-    var caseInSensitiveOutput = '<svg class="icon icon-activity-by-tag" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px" viewbox="0 0 100 100"><lineargradient><stop offset="0%"></stop><stop offset="50%"></stop></lineargradient></svg>';
+    var caseSensitiveOutput = '<div mixedCaseAttribute="value"></div>';
+    var caseInSensitiveOutput = '<div mixedcaseattribute="value"></div>';
 
     equal(minify(input), caseInSensitiveOutput);
     equal(minify(input, { caseSensitive: true }), caseSensitiveOutput);
     equal(minify(input, { removeOptionalTags: true }), output);
   });
 
+  test('mixed html and svg', function() {
+    input = '<html><body>\n' +
+      '  <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\n' +
+      '     width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174"\n' +
+      '     xml:space="preserve" class="logo">' +
+      '' +
+      '    <ellipse class="ground" cx="283.5" cy="487.5" rx="259" ry="80"/>' +
+      '    <polygon points="100,10 40,198 190,78 10,78 160,198"\n' +
+      '      style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;" />\n' +
+      '    <filter id="pictureFilter">\n' +
+      '      <feGaussianBlur stdDeviation="15" />\n' +
+      '    </filter>\n' +
+      '  </svg>\n' +
+      '</body></html>';
+
+    output = '<html><body>' +
+      '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174" xml:space="preserve" class="logo">' +
+      '<ellipse class="ground" cx="283.5" cy="487.5" rx="259" ry="80"/>' +
+      '<polygon points="100,10 40,198 190,78 10,78 160,198" style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd"/>' +
+      '<filter id="pictureFilter"><feGaussianBlur stdDeviation="15"/></filter>' +
+      '</svg>' +
+      '</body></html>';
+
+    // Should preserve case-sensitivity and closing slashes within svg tags
+    equal(minify(input, { collapseWhitespace: true }), output);
+  });
+
   test('nested quotes', function() {
     input = '<div data=\'{"test":"\\"test\\""}\'></div>';
     output = '<div data="{&quot;test&quot;:&quot;\\&quot;test\\&quot;&quot;}"></div>';