Do not strip conditional comments (write tests for it and mention on a main page).
authorJuriy Zaytsev <kangax@gmail.com>
Thu, 11 Feb 2010 18:30:57 +0000 (13:30 -0500)
committerJuriy Zaytsev <kangax@gmail.com>
Thu, 11 Feb 2010 18:30:57 +0000 (13:30 -0500)
Fix CDATA sections.

index.html
src/htmlminifier.js
tests/index.html

index f7dad7e..3f65e02 100644 (file)
@@ -20,6 +20,9 @@
               <label for="remove-comments">Remove comments (</label>
               <input type="checkbox" id="remove-comments-from-cdata" checked>
               <label for="remove-comments-from-cdata">also from scripts and styles )</label>
+              <span class="quiet short" style="margin-left:1.5em">
+                Conditional comments are left intact.
+              </span>
             </li>
             <li>
               <input type="checkbox" id="remove-cdata-sections-from-cdata" checked>
       <div id="todo">
         TODO:
         <ul>
-          <li>Write more unit tests (~60 so far)</li>
+          <li>Write more unit tests (~70 so far)</li>
           <li>Detect repeating attributes (e.g. multiple styles, classes, etc.)</li>
           <li>Strip whitespace from attributes where allowed</li>
           <li>Report deprecated (or presentational) attributes (e.g.: <code>&lt;td width="..." height="..."></code>)</li>
           <li>Add option to collapse all whitespace to 1 character, instead of completely removing it (to preserve empty text nodes)</li>
           <li>Figure out when it is safe to remove optional closing tags, so that it doesn't affect document tree</li>
-          <li>Do not strip IE conditional comments</li>
+          <li>Support IE "Downlevel-revealed Conditional Comments"</li>
           <li>Remove as many empty/blank attributes as possible (not just core ones)</li>
           <li>Parser trips over xml declarations (need to ignore or strip them)</li>
           <li>Generate a report of all applied transformations</li>
index 37d281f..d9b419b 100644 (file)
   function trimWhitespace(str) {
     return (str.trim ? str.trim() : str.replace(/^\s+/, '').replace(/\s+$/, ''));
   }
+  
   function collapseWhitespace(str) {
     return str.replace(/\s+/g, ' ');
   }
   
+  function isConditionalComment(text) {
+    return /\[if[^]+\]/.test(text);
+  }
+  
   function canRemoveAttributeQuotes(value) {
     // http://www.w3.org/TR/html4/intro/sgmltut.html#attributes
     // avoid \w, which could match unicode in some implementations
           }
           if (options.removeCDATASectionsFromCDATA) {
             text = text
-              // /* <![[CDATA */ or // <![[CDATA
-              .replace(/^(?:\s*\/\*\s*<!\[\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[\[CDATA\[.*)/, '')
-              // /* ]]> */ or // ]]>
+              // "/* <![CDATA[ */" or "// <![CDATA["
+              .replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/, '')
+              // "/* ]]> */" or "// ]]>"
               .replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/, '');
           }
         }
         buffer.push(text);
       },
       comment: function( text ) {
-        buffer.push(options.removeComments ? '' : ('<!--' + text + '-->'));
+        if (options.removeComments && !isConditionalComment(text)) {
+          text = '';
+        }
+        else {
+          text = '<!--' + text + '-->';
+        }
+        buffer.push(text);
       },
       doctype: function(doctype) {
         buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespace(doctype));
index 19e1eca..862ce3b 100644 (file)
           var input = '<!-- test -->';
           equals(minify(input, { removeComments: true }), '');
           
-          var input = '<!-- foo --><div>baz</div><!-- bar\n\n moo -->';
+          input = '<!-- foo --><div>baz</div><!-- bar\n\n moo -->';
           equals(minify(input, { removeComments: true }), '<div>baz</div>');
           equals(minify(input, { removeComments: false }), input);
           
-          var input = '<p title="<!-- comment in attribute -->">foo</p>';
+          input = '<p title="<!-- comment in attribute -->">foo</p>';
           equals(minify(input, { removeComments: true }), input);
           
-          var input = '<script><!-- alert(1) --><\/script>';
+          input = '<script><!-- alert(1) --><\/script>';
           equals(minify(input, { removeComments: true }), input);
           
-          var input = '<STYLE><!-- alert(1) --><\/STYLE>';
+          input = '<STYLE><!-- alert(1) --><\/STYLE>';
           equals(minify(input, { removeComments: true }), '<style><!-- alert(1) --><\/style>');
         });
         
+        test('conditional comments', function(){
+          var input = '<!--[if IE 6]> test <![endif]-->';
+          equals(minify(input, { removeComments: true }), input);
+          
+          input = '<!--[if lt IE 5.5]> test <![endif]-->';
+          equals(minify(input, { removeComments: true }), input);
+          
+          input = '<!--[if (gt IE 5)&(lt IE 7)]> test <![endif]-->';
+          equals(minify(input, { removeComments: true }), input);
+        });
+        
         test('remove comments from scripts/styles', function(){
           var input = '<script><!--alert(1)--><\/script>';
           var output = '<script>alert(1)<\/script>';
         });
         
         test('remove CDATA sections from scripts/styles', function(){
-          var input = '<script>/*<![[CDATA[*/alert(1)/*]]>*/<\/script>';
+          var input = '<script>/*<![CDATA[*/alert(1)/*]]>*/<\/script>';
           var output = '<script>alert(1)<\/script>';
           equals(minify(input, { removeCDATASectionsFromCDATA: true }), output);
           
-          input = '<script>//<![[CDATA[\nalert(1)\n//]]><\/script>';
+          input = '<script>//<![CDATA[\nalert(1)\n//]]><\/script>';
           output = '<script>\nalert(1)\n<\/script>';
           equals(minify(input, { removeCDATASectionsFromCDATA: true }), output);
           
-          input = '<script type="text/javascript"> /* \n\t  <![[CDATA[  */ alert(1) /*  ]]>  */ \n <\/script>';
+          input = '<script type="text/javascript"> /* \n\t  <![CDATA[  */ alert(1) /*  ]]>  */ \n <\/script>';
           output = '<script type="text/javascript"> alert(1) <\/script>';
           equals(minify(input, { removeCDATASectionsFromCDATA: true }), output);
           
-          input = '<style>/* <![[CDATA[ */p { color: red } // ]]><\/style>';
-          output = '<style>p { color: red } </style>';
+          input = '<style>/* <![CDATA[ */p { color: red } // ]]><\/style>';
+          output = '<style>p { color: red } <\/style>';
+          equals(minify(input, { removeCDATASectionsFromCDATA: true }), output);
+          
+          input = '<script>\n\n//<![CDATA[\nalert(1)//]]><\/script>';
+          output = '<script>\nalert(1)<\/script>';
           equals(minify(input, { removeCDATASectionsFromCDATA: true }), output);
           
         });