Smarter collapseWhitespace - preserver space around inline tags
authorwill Farrell <will.farrell@gmail.com>
Mon, 8 Apr 2013 00:34:49 +0000 (20:34 -0400)
committerwill Farrell <will.farrell@gmail.com>
Mon, 8 Apr 2013 00:34:49 +0000 (20:34 -0400)
src/htmlminifier.js
src/htmlparser.js
tests/minifier.js

index f0bafa3..e172b70 100644 (file)
   function collapseWhitespace(str) {
     return str.replace(/\s+/g, ' ');
   }
+  
+  function collapseWhitespaceSmart(str, prevTag, nextTag) {
+       // array of tags that will maintain a single space outside of them
+       var tags = ['a', 'b', 'big', 'button', 'em', 'font','i',  'img', 'mark', 's', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'tt', 'u'];
+       
+       if (prevTag && (prevTag.substr(0,1) !== '/'
+               || ( prevTag.substr(0,1) === '/' && tags.indexOf(prevTag.substr(1)) === -1))) {
+               str = str.replace(/^\s+/, '');
+       }
+       
+       if (nextTag && (nextTag.substr(0,1) === '/'
+               || ( nextTag.substr(0,1) !== '/' && tags.indexOf(nextTag) === -1))) {
+               str = str.replace(/\s+$/, '');
+       } 
+       
+       if (prevTag && nextTag) {
+               // strip non space whitespace then compress spaces to one
+               return str.replace(/[\t\n\r]+/g, '').replace(/[ ]+/g, ' ');
+       }
+       
+    return str;
+  }
 
   function isConditionalComment(text) {
     return ((/\[if[^\]]+\]/).test(text) || (/\s*(<!\[endif\])$/).test(text));
         buffer.length = 0;
         currentChars = '';
       },
-      chars: function( text ) {
+      chars: function( text, prevTag, nextTag ) {
         if (currentTag === 'script' || currentTag === 'style') {
           if (options.removeCommentsFromCDATA) {
             text = removeComments(text, currentTag);
         }
         if (options.collapseWhitespace) {
           if (!stackNoTrimWhitespace.length && _canTrimWhitespace(currentTag, currentAttrs)) {
-            text = trimWhitespace(text);
+            text = (prevTag || nextTag) ? collapseWhitespaceSmart(text, prevTag, nextTag) : trimWhitespace(text);
           }
           if (!stackNoCollapseWhitespace.length && _canCollapseWhitespace(currentTag, currentAttrs)) {
             text = collapseWhitespace(text);
index 8ea0530..0559f59 100644 (file)
@@ -54,7 +54,7 @@
   var reCache = { }, stackedTag, re;
 
   var HTMLParser = global.HTMLParser = function( html, handler ) {
-    var index, chars, match, stack = [], last = html;
+    var index, chars, match, stack = [], last = html, prevTag, nextTag;
     stack.last = function(){
       return this[ this.length - 1 ];
     };
@@ -89,6 +89,7 @@
           if ( match ) {
             html = html.substring( match[0].length );
             match[0].replace( endTag, parseEndTag );
+            prevTag = '/'+match[1];
             chars = false;
           }
   
           if ( match ) {
             html = html.substring( match[0].length );
             match[0].replace( startTag, parseStartTag );
+            prevTag = match[1];
             chars = false;
           }
         }
           var text = index < 0 ? html : html.substring( 0, index );
           html = index < 0 ? "" : html.substring( index );
           
+          // next tag
+          tagMatch = html.match( startTag );
+          if (tagMatch) {
+               nextTag = tagMatch[1];
+          } else {
+               tagMatch = html.match( endTag );
+               if (tagMatch) {
+                 nextTag = '/'+tagMatch[1];
+               } else {
+                     nextTag = '';
+               }
+          }
+          
           if ( handler.chars )
-            handler.chars( text );
+               handler.chars(text, prevTag, nextTag);
+          
         }
 
       } else {
     }
     return obj;
   }
-})(typeof exports === 'undefined' ? this : exports);
\ No newline at end of file
+})(typeof exports === 'undefined' ? this : exports);
index 6369543..3ab1baf 100644 (file)
     input = '<p> foo    bar</p>';
     output = '<p>foo bar</p>';
     equal(minify(input, { collapseWhitespace: true }), output);
-
-    input = '<p> foo    <span>  blah    22 </span> bar <img src=""></p>';
-    output = '<p>foo<span>blah 22</span>bar<img src=""></p>';
+    
+    input = '<p> foo    <span>  blah     <i>   22</i>    </span> bar <img src=""></p>';
+    output = '<p>foo <span>blah <i>22</i></span> bar <img src=""></p>';
     equal(minify(input, { collapseWhitespace: true }), output);
 
     input = '<textarea> foo bar     baz \n\n   x \t    y </textarea>';