ignoreCustomFragments to handle <%...%> and <?...?>
authoralexlamsl <alexlamsl@gmail.com>
Tue, 16 Feb 2016 20:02:47 +0000 (04:02 +0800)
committeralexlamsl <alexlamsl@gmail.com>
Tue, 16 Feb 2016 20:03:18 +0000 (04:03 +0800)
fixes #495

README.md
dist/htmlminifier.js
dist/htmlminifier.min.js
src/htmlminifier.js
src/htmlparser.js
tests/minifier.js

index 7d4393a..cb8e677 100644 (file)
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
 | `minifyCSS`                    | Minify CSS in style elements and style attributes (uses [clean-css](https://github.com/GoalSmashers/clean-css)) | `false` (could be `true`, `false`, `Object` (options)) |
 | `minifyURLs`                   | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `Object` (options)) |
 | `ignoreCustomComments`         | Array of regex'es that allow to ignore certain comments, when matched  | `[ ]` |
-| `ignoreCustomFragments`        | Array of regex'es that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.)  | `[ ]` |
+| `ignoreCustomFragments`        | Array of regex'es that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.)  | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
 | `processScripts`               | Array of strings corresponding to types of script elements to process through minifier (e.g. `text/ng-template`, `text/x-handlebars-template`, etc.) | `[ ]` |
 | `maxLineLength`                | Specify a maximum line length. Compressed output will be split by newlines at valid HTML split-points. |
 | `customEventAttributes`        | Arrays of regex'es that allow to support custom event attributes for `minifyJS` (e.g. `ng-click`) | `[ /^on[a-z]{3,}$/ ]` |
index 94f0873..49061fc 100644 (file)
           }
         }
 
-        // Ignored elements?
-        if ( /^<\?/.test( html ) ) {
-          index = html.indexOf( '?>', 2 );
-          if ( index >= 0 ) {
-            if ( handler.chars ) {
-              handler.chars( html.substring( 0, index + 2 ) );
-            }
-            html = html.substring( index + 2 );
-            prevTag = '';
-            continue;
-          }
-        }
-
-        if ( /^<%/.test( html ) ) {
-          index = html.indexOf( '%>', 2 );
-          if ( index >= 0 ) {
-            if ( handler.chars ) {
-              handler.chars(html.substring( 0, index + 2) );
-            }
-            html = html.substring( index + 2 );
-            prevTag = '';
-            continue;
-          }
-        }
-
         // Doctype:
         if ( (match = doctype.exec( html )) ) {
           if ( handler.doctype ) {
     };
   }
 
-  function collapseWhitespace(str) {
+  function collapseWhitespaceAll(str) {
     return str ? str.replace(/[\t\n\r ]+/g, ' ') : str;
   }
 
     return createMap(values.split(/,/));
   }
 
-  // array of non-empty element tags that will maintain a single space outside of them
-  var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
-
-  function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
+  function collapseWhitespace(str, preserveLineBreaks, conservativeCollapse, trimLeft, trimRight, collapseAll) {
     var lineBreakBefore = '', lineBreakAfter = '';
 
-    if (options.preserveLineBreaks) {
+    if (preserveLineBreaks) {
       str = str.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/, function() {
         lineBreakBefore = '\n';
         return '';
       });
     }
 
-    if (prevTag && prevTag !== 'img' && prevTag !== 'input' && prevTag !== 'comment'
-      && (prevTag.charAt(0) !== '/' || options.collapseInlineTagWhitespace || !inlineTags(prevTag.substr(1)))) {
-      str = str.replace(/^\s+/, !lineBreakBefore && options.conservativeCollapse ? ' ' : '');
+    if (trimLeft) {
+      str = str.replace(/^\s+/, !lineBreakBefore && conservativeCollapse ? ' ' : '');
     }
 
-    if (nextTag && nextTag !== 'img' && nextTag !== 'input' && nextTag !== 'comment'
-      && (nextTag.charAt(0) === '/' || options.collapseInlineTagWhitespace || !inlineTags(nextTag))) {
-      str = str.replace(/\s+$/, !lineBreakAfter && options.conservativeCollapse ? ' ' : '');
+    if (trimRight) {
+      str = str.replace(/\s+$/, !lineBreakAfter && conservativeCollapse ? ' ' : '');
     }
 
-    if (prevTag && nextTag) {
+    if (collapseAll) {
       // strip non space whitespace then compress spaces to one
-      str = collapseWhitespace(str);
+      str = collapseWhitespaceAll(str);
     }
 
     return lineBreakBefore + str + lineBreakAfter;
   }
 
+  // array of non-empty element tags that will maintain a single space outside of them
+  var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
+  var selfClosingInlineTags = createMapFromString('comment,img,input');
+
+  function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
+    var trimLeft = prevTag && !selfClosingInlineTags(prevTag) && (options.collapseInlineTagWhitespace || prevTag.charAt(0) !== '/' || !inlineTags(prevTag.substr(1)));
+    var trimRight = nextTag && !selfClosingInlineTags(nextTag) && (options.collapseInlineTagWhitespace || nextTag.charAt(0) === '/' || !inlineTags(nextTag));
+    return collapseWhitespace(str, options.preserveLineBreaks, options.conservativeCollapse, trimLeft, trimRight, prevTag && nextTag);
+  }
+
   function isConditionalComment(text) {
     return ((/\[if[^\]]+\]/).test(text) || (/\s*((?:<!)?\[endif\])$/).test(text));
   }
       return attrValue;
     }
     else if (attrName === 'class') {
-      return collapseWhitespace(trimWhitespace(attrValue));
+      return collapseWhitespaceAll(trimWhitespace(attrValue));
     }
     else if (isUriTypeAttribute(attrName, tag)) {
       attrValue = trimWhitespace(attrValue);
       });
     }
 
-    if (options.ignoreCustomFragments) {
-      uidAttr = uniqueId(value);
-      var customFragments = options.ignoreCustomFragments.map(function(re) {
-        return re.source;
-      });
+    var customFragments = (options.ignoreCustomFragments || [
+      /<%[\s\S]*?%>/,
+      /<\?[\s\S]*?\?>/
+    ]).map(function(re) {
+      return re.source;
+    });
+    if (customFragments.length) {
       var reCustomIgnore = new RegExp('\\s*(?:' + customFragments.join('|') + ')\\s*', 'g');
       // temporarily replace custom ignored fragments with unique attributes
       value = value.replace(reCustomIgnore, function(match) {
+        if (!uidAttr) {
+          uidAttr = uniqueId(value);
+        }
         ignoredCustomMarkupChunks.push(match);
         return ' ' + uidAttr + ' ';
       });
             text = prevTag || nextTag ? collapseWhitespaceSmart(text, prevTag, nextTag, options) : trimWhitespace(text);
           }
           if (!stackNoCollapseWhitespace.length) {
-            text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespace(text);
+            text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespaceAll(text);
           }
         }
         if (currentTag === 'script' || currentTag === 'style') {
         buffer.push(text);
       },
       doctype: function(doctype) {
-        buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespace(doctype));
+        buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespaceAll(doctype));
       },
       customAttrAssign: options.customAttrAssign,
       customAttrSurround: options.customAttrSurround
     var str = joinResultSegments(results, options);
 
     if (uidAttr) {
-      str = str.replace(new RegExp('\\s*' + uidAttr + '\\s*', 'g'), function() {
-        return ignoredCustomMarkupChunks.shift();
+      str = str.replace(new RegExp('(\\s*)' + uidAttr + '(\\s*)', 'g'), function(match, prefix, suffix) {
+        var chunk = ignoredCustomMarkupChunks.shift();
+        return options.collapseWhitespace ? collapseWhitespace(prefix + chunk + suffix, options.preserveLineBreaks, true, true, true) : chunk;
       });
     }
     if (uidIgnore) {
index 20c473a..2a19ea5 100644 (file)
@@ -3,4 +3,4 @@
  * Copyright 2010-2016 Juriy "kangax" Zaytsev
  * Licensed under the MIT license
  */
-!function(a){"use strict";function b(a){var b,c=new RegExp("(?:\\s*[\\w:\\.-]+(?:\\s*(?:"+d(a)+")\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*");if(a.customAttrSurround){for(var e=[],f=a.customAttrSurround.length-1;f>=0;f--)e[f]="(?:\\s*"+a.customAttrSurround[f][0].source+"\\s*"+c.source+"\\s*"+a.customAttrSurround[f][1].source+")";e.unshift(c.source),b=new RegExp("((?:"+e.join("|")+")*)")}else b=new RegExp("("+c.source+")");return new RegExp(j.source+b.source+k.source)}function c(a){var b=new RegExp(f.source+"(?:\\s*("+d(a)+")\\s*(?:"+i.join("|")+"))?");if(a.customAttrSurround){for(var c=[],e=a.customAttrSurround.length-1;e>=0;e--)c[e]="(?:("+a.customAttrSurround[e][0].source+")\\s*"+b.source+"\\s*("+a.customAttrSurround[e][1].source+"))";return c.unshift("(?:"+b.source+")"),new RegExp(c.join("|"),"g")}return new RegExp(b.source,"g")}function d(a){return h.concat(a.customAttrAssign||[]).map(function(a){return"(?:"+a.source+")"}).join("|")}function e(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var f=/([\w:\.-]+)/,g=/=/,h=[g],i=[/"((?:\\.|[^"])*)"/.source,/'((?:\\.|[^'])*)'/.source,/([^>\s]+)/.source],j=/^<([\w:-]+)/,k=/\s*(\/?)>/,l=/^<\/([\w:-]+)[^>]*>/,m=/\/>$/,n=/^<!DOCTYPE [^>]+>/i,o=!1;"x".replace(/x(.)?/g,function(a,b){o=""===b});var p,q,r,s=e("area,base,basefont,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),t=e("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var"),u=e("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),v=e("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),w=e("script,style"),x={},y=a.HTMLParser=function(a,d){function e(a,b,c,e){for(var g=!1;!d.html5&&k.last()&&t[k.last()];)f("",k.last());u[b]&&k.last()===b&&f("",b),e=s[b]||!!e;var h=[];c.replace(A,function(){var a,b,c,e,f,g,i,j=7;if(o&&-1===arguments[0].indexOf('""')&&(""===arguments[3]&&(arguments[3]=void 0),""===arguments[4]&&(arguments[4]=void 0),""===arguments[5]&&(arguments[5]=void 0)),a=arguments[1])g=arguments[2],c=arguments[3],b=c||arguments[4]||arguments[5],g&&(i=arguments[0].charAt(a.length+g.length),i="'"===i||'"'===i?i:"");else if(d.customAttrSurround)for(var k=d.customAttrSurround.length-1;k>=0;k--)if(a=arguments[k*j+7],g=arguments[k*j+8],a){c=arguments[k*j+9],b=c||arguments[k*j+10]||arguments[k*j+11],e=arguments[k*j+6],f=arguments[k*j+12];break}void 0===b&&(b=v[a]?a:c),h.push({name:a,value:b,customAssign:g||"=",customOpen:e||"",customClose:f||"",quote:i||""})}),e?g=a.match(m):k.push({tag:b,attrs:h}),d.start&&d.start(b,h,e,g)}function f(a,b){var c;if(b){var e=b.toLowerCase();for(c=k.length-1;c>=0&&k[c].tag.toLowerCase()!==e;c--);}else c=0;if(c>=0){for(var f=k.length-1;f>=c;f--)d.end&&d.end(k[f].tag,k[f].attrs);k.length=c}}var g,h,i,j,k=[],y=a;k.last=function(){var a=this[this.length-1];return a&&a.tag};for(var z=b(d),A=c(d);a;){if(k.last()&&w[k.last()])p=k.last().toLowerCase(),q=x[p]||(x[p]=new RegExp("([\\s\\S]*?)</"+p+"[^>]*>","i")),a=a.replace(q,function(a,b){return"script"!==p&&"style"!==p&&"noscript"!==p&&(b=b.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),d.chars&&d.chars(b),""}),f("",p);else{if(/^<!--/.test(a)&&(g=a.indexOf("-->"),g>=0)){d.comment&&d.comment(a.substring(4,g)),a=a.substring(g+3),i="";continue}if(/^<!\[/.test(a)&&(g=a.indexOf("]>"),g>=0)){d.comment&&d.comment(a.substring(2,g+1),!0),a=a.substring(g+2),i="";continue}if(/^<\?/.test(a)&&(g=a.indexOf("?>",2),g>=0)){d.chars&&d.chars(a.substring(0,g+2)),a=a.substring(g+2),i="";continue}if(/^<%/.test(a)&&(g=a.indexOf("%>",2),g>=0)){d.chars&&d.chars(a.substring(0,g+2)),a=a.substring(g+2),i="";continue}if(h=n.exec(a)){d.doctype&&d.doctype(h[0]),a=a.substring(h[0].length),i="";continue}if(/^<\//.test(a)&&(h=a.match(l))){a=a.substring(h[0].length),h[0].replace(l,f),i="/"+h[1].toLowerCase();continue}if(/^</.test(a)&&(h=a.match(z))){a=a.substring(h[0].length),h[0].replace(z,e),i=h[1].toLowerCase();continue}g=a.indexOf("<");var B=0>g?a:a.substring(0,g);a=0>g?"":a.substring(g),r=a.match(z),r?j=r[1]:(r=a.match(l),j=r?"/"+r[1]:""),d.chars&&d.chars(B,i,j),i=""}if(a===y)throw"Parse Error: "+a;y=a}f()};a.HTMLtoXML=function(a){var b="";return new y(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+(c[e].value||"").replace(/"/g,"&#34;")+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,b){var c=e("html,head,body,title"),d={link:"head",base:"head"};b?b=b.ownerDocument||b.getOwnerDocument&&b.getOwnerDocument()||b:"undefined"!=typeof DOMDocument?b=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?b=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(b=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=b.documentElement||b.getDocumentElement&&b.getDocumentElement();if(!g&&b.createElement&&!function(){var a=b.createElement("html"),c=b.createElement("head");c.appendChild(b.createElement("title")),a.appendChild(c),a.appendChild(b.createElement("body")),b.appendChild(a)}(),b.getElementsByTagName)for(var h in c)c[h]=b.getElementsByTagName(h)[0];var i=c.body;return new y(a,{start:function(a,e,g){if(c[a])return void(i=c[a]);var h=b.createElement(a);for(var j in e)h.setAttribute(e[j].name,e[j].value);d[a]&&"boolean"!=typeof c[d[a]]?c[d[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(b.createTextNode(a))},comment:function(){},ignore:function(){}}),b}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a?a.replace(/[\t\n\r ]+/g," "):a}function c(a){var b={};return a.forEach(function(a){b[a]=1}),function(a){return 1===b[a]}}function d(a){return c(a.split(/,/))}function e(a,c,d,e){var f="",g="";return e.preserveLineBreaks&&(a=a.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/,function(){return f="\n",""}).replace(/[\t\n\r ]*[\n\r]+[\t ]*$/,function(){return g="\n",""})),!c||"img"===c||"input"===c||"comment"===c||"/"===c.charAt(0)&&!e.collapseInlineTagWhitespace&&Q(c.substr(1))||(a=a.replace(/^\s+/,!f&&e.conservativeCollapse?" ":"")),!d||"img"===d||"input"===d||"comment"===d||"/"!==d.charAt(0)&&!e.collapseInlineTagWhitespace&&Q(d)||(a=a.replace(/\s+$/,!g&&e.conservativeCollapse?" ":"")),c&&d&&(a=b(a)),f+a+g}function f(a){return/\[if[^\]]+\]/.test(a)||/\s*((?:<!)?\[endif\])$/.test(a)}function g(a,b){if(/^!/.test(a))return!0;if(b.ignoreCustomComments)for(var c=0,d=b.ignoreCustomComments.length;d>c;c++)if(b.ignoreCustomComments[c].test(a))return!0;return!1}function h(a,b){var c=b.customEventAttributes;if(c){for(var d=c.length;d--;)if(c[d].test(a))return!0;return!1}return/^on[a-z]{3,}$/.test(a)}function i(a){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)}function j(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function k(a,b,c,d){return c=c?P(c.toLowerCase()):"","script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!j(d,"src")||"a"===a&&"name"===b&&j(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function l(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===P(c.toLowerCase())}function m(a,b){if("script"!==a)return!1;for(var c=0,d=b.length;d>c;c++){var e=b[c].name.toLowerCase();if("type"===e){var f=P(b[c].value).split(/;/,2)[0].toLowerCase();return""===f||R(f)}}return!0}function n(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===P(c.toLowerCase())}function o(a,b){var c=/^(?: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|truespeed|typemustmatch|visible)$/i.test(a);if(c)return!0;var d=S[a.toLowerCase()];return d?-1===d.indexOf(b.toLowerCase()):!1}function p(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function q(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function r(a,b){if("link"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("rel"===b[c].name&&"canonical"===b[c].value)return!0}function s(a,c,d,e,f){if(d&&h(c,e)){if(d=P(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""),e.minifyJS){var g=I(T+d+U,e.minifyJS);return g.slice(T.length,-U.length)}return d}return"class"===c?b(P(d)):p(c,a)?(d=P(d),e.minifyURLs&&!r(a,f)?H(d,e.minifyURLs):d):q(c,a)?P(d):"style"===c?(d=P(d),d&&(d=d.replace(/\s*;\s*$/,"")),e.minifyCSS?J(d,e.minifyCSS,!0):d):(t(a,f)&&"content"===c?d=d.replace(/\s+/g,"").replace(/[0-9]+\.[0-9]+/g,function(a){return(+a).toString()}):d&&e.customAttrCollapse&&e.customAttrCollapse.test(c)&&(d=d.replace(/\n+|\r+|\s{2,}/g,"")),d)}function t(a,b){if("meta"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("name"===b[c].name&&"viewport"===b[c].value)return!0}function u(a){return"*{"+a+"}"}function v(a){var b=a.match(/^\*\{([\s\S]*)\}$/m);return b&&b[1]?b[1]:a}function w(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function x(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function y(a,b,c){for(var d=0,e=c.length;e>d;d++)if("type"===c[d].name.toLowerCase()&&b.processScripts.indexOf(c[d].value)>-1)return L(a,b);return a}function z(a,b){return a.replace(V[b],"").replace(W[b],"")}function A(a,b){switch(a){case"html":case"head":case"body":case"colgroup":return!0;case"li":case"optgroup":case"tr":return b===a;case"dt":case"dd":return $(b);case"p":return _(b);case"rb":case"rt":case"rp":return aa(b);case"rtc":return ba(b);case"option":return ca(b);case"thead":case"tbody":return da(b);case"tfoot":return"tbody"===b;case"td":case"th":return ea(b)}return!1}function B(a,b,c){var d=!c||/^\s*$/.test(c);return d?"input"===a&&"value"===b||fa.test(b):!1}function C(a,b){if("textarea"===a)return!1;if("script"===a)for(var c=b.length-1;c>=0;c--)if("src"===b[c].name)return!1;return!0}function D(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function E(a){return!/^(?:pre|textarea)$/.test(a)}function F(a,b,c,d,e,f,g){var h,j,m=f.caseSensitive?a.name:a.name.toLowerCase(),p=a.value,q=a.quote;if(f.removeRedundantAttributes&&k(c,m,p,b)||f.removeScriptTypeAttributes&&l(c,m,p)||f.removeStyleLinkTypeAttributes&&n(c,m,p))return"";if(p=s(c,m,p,f,b),f.removeEmptyAttributes&&B(c,m,p))return"";if(void 0!==p&&!f.removeAttributeQuotes||!i(p)){if(!f.preventAttributesEscaping){if(void 0!==f.quoteCharacter)q="'"===f.quoteCharacter?"'":'"';else{var r=(p.match(/'/g)||[]).length,t=(p.match(/"/g)||[]).length;q=t>r?"'":'"'}p='"'===q?p.replace(/"/g,"&#34;"):p.replace(/'/g,"&#39;")}j=q+p+q,g||f.removeTagWhitespace||(j+=" ")}else j=!g||d||/\/$/.test(p)?p+" ":p;return void 0===p||f.collapseBooleanAttributes&&o(m,p)?(h=m,g||(h+=" ")):h=m+a.customAssign+j,a.customOpen+h+a.customClose}function G(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function H(b,c){"object"!=typeof c&&(c={});try{var d=a.RelateUrl;return"undefined"==typeof d&&"function"==typeof require&&(d=require("relateurl")),d&&d.relate?d.relate(b,c):b}catch(e){N(e)}return b}function I(b,c){"object"!=typeof c&&(c={}),c.fromString=!0;var d=c.output||{};d.inline_script=!0,c.output=d;try{var e=a.UglifyJS;if("undefined"==typeof e&&"function"==typeof require&&(e=require("uglify-js")),!e)return b;if(e.minify)return e.minify(b,c).code;if(e.parse){var f=e.parse(b);f.figure_out_scope();var g=e.Compressor(),h=f.transform(g);h.figure_out_scope(),h.compute_char_frequency(),c.mangle!==!1&&h.mangle_names();var i=e.OutputStream(c.output);return h.print(i),i.toString()}return b}catch(j){N(j)}return b}function J(a,b,c){"object"!=typeof b&&(b={}),"undefined"==typeof b.advanced&&(b.advanced=!1);try{var d;if("undefined"!=typeof CleanCSS)d=new CleanCSS(b);else if("function"==typeof require){var e=require("clean-css");d=new e(b)}return c?v(d.minify(u(a)).styles):d.minify(a).styles}catch(f){N(f)}return a}function K(a){var b;do b=Math.random().toString(36).slice(2);while(~a.indexOf(b));return b}function L(a,c){function d(a,b){return D(a)||c.canCollapseWhitespace(a,b)}function h(a,b){return E(a)||c.canTrimWhitespace(a,b)}function i(){for(var a=q.length-1;a>0&&!/^<[^\/!]/.test(q[a]);)a--;q.length=Math.max(0,a)}function j(){for(var a=q.length-1;a>0&&!/^<\//.test(q[a]);)a--;q.length=a}c=c||{};var k=[];a=P(a),G(c);var l,n,o,p=[],q=[],r="",s="",t=[],u=[],v=[],B="",H="",L=c.lint,Q=Date.now(),R=[],S=[];if(~a.indexOf("<!-- htmlmin:ignore -->")&&(n="<!--!"+K(a)+"-->",a=a.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,function(a,b){return R.push(b),n})),c.ignoreCustomFragments){o=K(a);var T=c.ignoreCustomFragments.map(function(a){return a.source}),U=new RegExp("\\s*(?:"+T.join("|")+")\\s*","g");a=a.replace(U,function(a){return S.push(a)," "+o+" "})}new O(a,{html5:"undefined"!=typeof c.html5?c.html5:!0,start:function(a,b,e,f){var g=a.toLowerCase();if("svg"===g){k.push(c);var m={};for(var n in c)m[n]=c[n];m.keepClosingSlash=!0,m.caseSensitive=!0,c=m}a=c.caseSensitive?a:g,s=a,l=a,r="",t=b,c.removeOptionalTags&&(!B||"body"===B&&Z(a)||i(),B="",A(H,a)&&j(),H=""),c.collapseWhitespace&&(h(a,b)||u.push(a),d(a,b)||v.push(a));var o="<"+a,p=f&&c.keepClosingSlash;q.push(o),L&&L.testElement(a);for(var w,x=[],y=!0,z=b.length;--z>=0;)L&&L.testAttribute(a,b[z].name.toLowerCase(),b[z].value),w=F(b[z],b,a,p,z,c,y),w&&(y=!1,x.unshift(w));x.length>0?(q.push(" "),q.push.apply(q,x)):c.removeOptionalTags&&X(a)&&(B=a),q.push(q.pop()+(p?"/":"")+">")},end:function(a,b){var d=a.toLowerCase();if("svg"===d&&(c=k.pop()),a=c.caseSensitive?a:d,c.removeOptionalTags&&(!H||"dt"===H||"thead"===H||"p"===H&&"a"===a||j(),H=Y(a)?a:""),c.collapseWhitespace){if(u.length)a===u[u.length-1]&&u.pop();else{var f;q.length>1&&""===q[q.length-1]&&/\s+$/.test(q[q.length-2])?f=q.length-2:q.length>0&&/\s+$/.test(q[q.length-1])&&(f=q.length-1),f>0&&(q[f]=q[f].replace(/\s+$/,function(b){return e(b,"comment","/"+a,c)}))}v.length&&a===v[v.length-1]&&v.pop()}var g=!1;a===s&&(s="",g=""===r),c.removeEmptyElements&&g&&C(a,b)?(i(),B="",H=""):(p.push.apply(p,q),q=["</"+a+">"],l="/"+a,r="")},chars:function(a,d,f){if(d=""===d?"comment":d,f=""===f?"comment":f,c.collapseWhitespace){if(!u.length){if("comment"===d){var g=""===q[q.length-1];if(g&&(d=l),q.length>1&&(g||" "===r.charAt(r.length-1))){var h=q.length-2;q[h]=q[h].replace(/\s+$/,function(b){return a=b+a,""})}}a=d||f?e(a,d,f,c):P(a)}v.length||(a=d&&f||"html"===f?a:b(a))}("script"===s||"style"===s)&&(c.removeCommentsFromCDATA&&(a=z(a,s)),c.removeCDATASectionsFromCDATA&&(a=x(a)),c.processScripts&&(a=y(a,c,t))),c.minifyJS&&m(s,t)&&(a=I(a,c.minifyJS),";"===a.charAt(a.length-1)&&(a=a.slice(0,-1))),"style"===s&&c.minifyCSS&&(a=J(a,c.minifyCSS)),c.removeOptionalTags&&a&&(("html"===B||"body"===B&&!/^\s/.test(a))&&i(),B="","html"!==H&&"body"!==H&&("head"!==H&&"colgroup"!==H||/^\s/.test(a))||j(),H=""),l=/^\s*$/.test(a)?d:"comment",r+=a,L&&L.testChars(a),q.push(a)},comment:function(a,b){var d=b?"<!":"<!--",e=b?">":"-->";a=c.removeComments?f(a)?d+w(a)+e:g(a,c)?"<!--"+a+"-->":"":d+a+e,c.removeOptionalTags&&a&&(B="",H=""),q.push(a)},doctype:function(a){q.push(c.useShortDoctype?"<!DOCTYPE html>":b(a))},customAttrAssign:c.customAttrAssign,customAttrSurround:c.customAttrSurround}),c.removeOptionalTags&&(B&&i(),H&&"dt"!==H&&"thead"!==H&&j()),p.push.apply(p,q);var V=M(p,c);return o&&(V=V.replace(new RegExp("\\s*"+o+"\\s*","g"),function(){return S.shift()})),n&&(V=V.replace(new RegExp(n,"g"),function(){return R.shift()})),N("minified in: "+(Date.now()-Q)+"ms"),V}function M(a,b){var c,d=b.maxLineLength;if(d){for(var e,f=[],g="",h=0,i=a.length;i>h;h++)e=a[h],g.length+e.length<d?g+=e:(f.push(g.replace(/^\n/,"")),g=e);f.push(g),c=f.join("\n")}else c=a.join("");return P(c)}var N,O;N=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?O=a.HTMLParser:"function"==typeof require&&(O=require("./htmlparser").HTMLParser);var P=function(a){return"string"!=typeof a?a:a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(P=function(a){return"string"!=typeof a?a:a.trim()});var Q=d("a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var"),R=c(["text/javascript","text/ecmascript","text/jscript","application/javascript","application/x-javascript","application/ecmascript"]),S={draggable:["true","false"]},T="!function(){",U="}();",V={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},W={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},X=d("html,head,body"),Y=d("html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,thead,tbody,tfoot,tr,td,th"),Z=d("meta,link,script,style,template"),$=d("dt,dd"),_=d("address,article,aside,blockquote,div,dl,fieldset,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,main,nav,ol,p,pre,section,table,ul"),aa=d("rb,rt,rtc,rp"),ba=d("rb,rtc,rp"),ca=d("option,optgroup"),da=d("tbody,tfoot"),ea=d("td,th"),fa=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=L:a.minify=L}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return/^(?:big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|strike)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
\ No newline at end of file
+!function(a){"use strict";function b(a){var b,c=new RegExp("(?:\\s*[\\w:\\.-]+(?:\\s*(?:"+d(a)+")\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*");if(a.customAttrSurround){for(var e=[],f=a.customAttrSurround.length-1;f>=0;f--)e[f]="(?:\\s*"+a.customAttrSurround[f][0].source+"\\s*"+c.source+"\\s*"+a.customAttrSurround[f][1].source+")";e.unshift(c.source),b=new RegExp("((?:"+e.join("|")+")*)")}else b=new RegExp("("+c.source+")");return new RegExp(j.source+b.source+k.source)}function c(a){var b=new RegExp(f.source+"(?:\\s*("+d(a)+")\\s*(?:"+i.join("|")+"))?");if(a.customAttrSurround){for(var c=[],e=a.customAttrSurround.length-1;e>=0;e--)c[e]="(?:("+a.customAttrSurround[e][0].source+")\\s*"+b.source+"\\s*("+a.customAttrSurround[e][1].source+"))";return c.unshift("(?:"+b.source+")"),new RegExp(c.join("|"),"g")}return new RegExp(b.source,"g")}function d(a){return h.concat(a.customAttrAssign||[]).map(function(a){return"(?:"+a.source+")"}).join("|")}function e(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var f=/([\w:\.-]+)/,g=/=/,h=[g],i=[/"((?:\\.|[^"])*)"/.source,/'((?:\\.|[^'])*)'/.source,/([^>\s]+)/.source],j=/^<([\w:-]+)/,k=/\s*(\/?)>/,l=/^<\/([\w:-]+)[^>]*>/,m=/\/>$/,n=/^<!DOCTYPE [^>]+>/i,o=!1;"x".replace(/x(.)?/g,function(a,b){o=""===b});var p,q,r,s=e("area,base,basefont,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),t=e("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var"),u=e("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),v=e("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),w=e("script,style"),x={},y=a.HTMLParser=function(a,d){function e(a,b,c,e){for(var g=!1;!d.html5&&k.last()&&t[k.last()];)f("",k.last());u[b]&&k.last()===b&&f("",b),e=s[b]||!!e;var h=[];c.replace(A,function(){var a,b,c,e,f,g,i,j=7;if(o&&-1===arguments[0].indexOf('""')&&(""===arguments[3]&&(arguments[3]=void 0),""===arguments[4]&&(arguments[4]=void 0),""===arguments[5]&&(arguments[5]=void 0)),a=arguments[1])g=arguments[2],c=arguments[3],b=c||arguments[4]||arguments[5],g&&(i=arguments[0].charAt(a.length+g.length),i="'"===i||'"'===i?i:"");else if(d.customAttrSurround)for(var k=d.customAttrSurround.length-1;k>=0;k--)if(a=arguments[k*j+7],g=arguments[k*j+8],a){c=arguments[k*j+9],b=c||arguments[k*j+10]||arguments[k*j+11],e=arguments[k*j+6],f=arguments[k*j+12];break}void 0===b&&(b=v[a]?a:c),h.push({name:a,value:b,customAssign:g||"=",customOpen:e||"",customClose:f||"",quote:i||""})}),e?g=a.match(m):k.push({tag:b,attrs:h}),d.start&&d.start(b,h,e,g)}function f(a,b){var c;if(b){var e=b.toLowerCase();for(c=k.length-1;c>=0&&k[c].tag.toLowerCase()!==e;c--);}else c=0;if(c>=0){for(var f=k.length-1;f>=c;f--)d.end&&d.end(k[f].tag,k[f].attrs);k.length=c}}var g,h,i,j,k=[],y=a;k.last=function(){var a=this[this.length-1];return a&&a.tag};for(var z=b(d),A=c(d);a;){if(k.last()&&w[k.last()])p=k.last().toLowerCase(),q=x[p]||(x[p]=new RegExp("([\\s\\S]*?)</"+p+"[^>]*>","i")),a=a.replace(q,function(a,b){return"script"!==p&&"style"!==p&&"noscript"!==p&&(b=b.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),d.chars&&d.chars(b),""}),f("",p);else{if(/^<!--/.test(a)&&(g=a.indexOf("-->"),g>=0)){d.comment&&d.comment(a.substring(4,g)),a=a.substring(g+3),i="";continue}if(/^<!\[/.test(a)&&(g=a.indexOf("]>"),g>=0)){d.comment&&d.comment(a.substring(2,g+1),!0),a=a.substring(g+2),i="";continue}if(h=n.exec(a)){d.doctype&&d.doctype(h[0]),a=a.substring(h[0].length),i="";continue}if(/^<\//.test(a)&&(h=a.match(l))){a=a.substring(h[0].length),h[0].replace(l,f),i="/"+h[1].toLowerCase();continue}if(/^</.test(a)&&(h=a.match(z))){a=a.substring(h[0].length),h[0].replace(z,e),i=h[1].toLowerCase();continue}g=a.indexOf("<");var B=0>g?a:a.substring(0,g);a=0>g?"":a.substring(g),r=a.match(z),r?j=r[1]:(r=a.match(l),j=r?"/"+r[1]:""),d.chars&&d.chars(B,i,j),i=""}if(a===y)throw"Parse Error: "+a;y=a}f()};a.HTMLtoXML=function(a){var b="";return new y(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+(c[e].value||"").replace(/"/g,"&#34;")+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,b){var c=e("html,head,body,title"),d={link:"head",base:"head"};b?b=b.ownerDocument||b.getOwnerDocument&&b.getOwnerDocument()||b:"undefined"!=typeof DOMDocument?b=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?b=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(b=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=b.documentElement||b.getDocumentElement&&b.getDocumentElement();if(!g&&b.createElement&&!function(){var a=b.createElement("html"),c=b.createElement("head");c.appendChild(b.createElement("title")),a.appendChild(c),a.appendChild(b.createElement("body")),b.appendChild(a)}(),b.getElementsByTagName)for(var h in c)c[h]=b.getElementsByTagName(h)[0];var i=c.body;return new y(a,{start:function(a,e,g){if(c[a])return void(i=c[a]);var h=b.createElement(a);for(var j in e)h.setAttribute(e[j].name,e[j].value);d[a]&&"boolean"!=typeof c[d[a]]?c[d[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(b.createTextNode(a))},comment:function(){},ignore:function(){}}),b}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a?a.replace(/[\t\n\r ]+/g," "):a}function c(a){var b={};return a.forEach(function(a){b[a]=1}),function(a){return 1===b[a]}}function d(a){return c(a.split(/,/))}function e(a,c,d,e,f,g){var h="",i="";return c&&(a=a.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/,function(){return h="\n",""}).replace(/[\t\n\r ]*[\n\r]+[\t ]*$/,function(){return i="\n",""})),e&&(a=a.replace(/^\s+/,!h&&d?" ":"")),f&&(a=a.replace(/\s+$/,!i&&d?" ":"")),g&&(a=b(a)),h+a+i}function f(a,b,c,d){var f=b&&!S(b)&&(d.collapseInlineTagWhitespace||"/"!==b.charAt(0)||!R(b.substr(1))),g=c&&!S(c)&&(d.collapseInlineTagWhitespace||"/"===c.charAt(0)||!R(c));return e(a,d.preserveLineBreaks,d.conservativeCollapse,f,g,b&&c)}function g(a){return/\[if[^\]]+\]/.test(a)||/\s*((?:<!)?\[endif\])$/.test(a)}function h(a,b){if(/^!/.test(a))return!0;if(b.ignoreCustomComments)for(var c=0,d=b.ignoreCustomComments.length;d>c;c++)if(b.ignoreCustomComments[c].test(a))return!0;return!1}function i(a,b){var c=b.customEventAttributes;if(c){for(var d=c.length;d--;)if(c[d].test(a))return!0;return!1}return/^on[a-z]{3,}$/.test(a)}function j(a){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)}function k(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function l(a,b,c,d){return c=c?Q(c.toLowerCase()):"","script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!k(d,"src")||"a"===a&&"name"===b&&k(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function m(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===Q(c.toLowerCase())}function n(a,b){if("script"!==a)return!1;for(var c=0,d=b.length;d>c;c++){var e=b[c].name.toLowerCase();if("type"===e){var f=Q(b[c].value).split(/;/,2)[0].toLowerCase();return""===f||T(f)}}return!0}function o(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===Q(c.toLowerCase())}function p(a,b){var c=/^(?: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|truespeed|typemustmatch|visible)$/i.test(a);if(c)return!0;var d=U[a.toLowerCase()];return d?-1===d.indexOf(b.toLowerCase()):!1}function q(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function r(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function s(a,b){if("link"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("rel"===b[c].name&&"canonical"===b[c].value)return!0}function t(a,c,d,e,f){if(d&&i(c,e)){if(d=Q(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""),e.minifyJS){var g=J(V+d+W,e.minifyJS);return g.slice(V.length,-W.length)}return d}return"class"===c?b(Q(d)):q(c,a)?(d=Q(d),e.minifyURLs&&!s(a,f)?I(d,e.minifyURLs):d):r(c,a)?Q(d):"style"===c?(d=Q(d),d&&(d=d.replace(/\s*;\s*$/,"")),e.minifyCSS?K(d,e.minifyCSS,!0):d):(u(a,f)&&"content"===c?d=d.replace(/\s+/g,"").replace(/[0-9]+\.[0-9]+/g,function(a){return(+a).toString()}):d&&e.customAttrCollapse&&e.customAttrCollapse.test(c)&&(d=d.replace(/\n+|\r+|\s{2,}/g,"")),d)}function u(a,b){if("meta"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("name"===b[c].name&&"viewport"===b[c].value)return!0}function v(a){return"*{"+a+"}"}function w(a){var b=a.match(/^\*\{([\s\S]*)\}$/m);return b&&b[1]?b[1]:a}function x(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function y(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function z(a,b,c){for(var d=0,e=c.length;e>d;d++)if("type"===c[d].name.toLowerCase()&&b.processScripts.indexOf(c[d].value)>-1)return M(a,b);return a}function A(a,b){return a.replace(X[b],"").replace(Y[b],"")}function B(a,b){switch(a){case"html":case"head":case"body":case"colgroup":return!0;case"li":case"optgroup":case"tr":return b===a;case"dt":case"dd":return aa(b);case"p":return ba(b);case"rb":case"rt":case"rp":return ca(b);case"rtc":return da(b);case"option":return ea(b);case"thead":case"tbody":return fa(b);case"tfoot":return"tbody"===b;case"td":case"th":return ga(b)}return!1}function C(a,b,c){var d=!c||/^\s*$/.test(c);return d?"input"===a&&"value"===b||ha.test(b):!1}function D(a,b){if("textarea"===a)return!1;if("script"===a)for(var c=b.length-1;c>=0;c--)if("src"===b[c].name)return!1;return!0}function E(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function F(a){return!/^(?:pre|textarea)$/.test(a)}function G(a,b,c,d,e,f,g){var h,i,k=f.caseSensitive?a.name:a.name.toLowerCase(),n=a.value,q=a.quote;if(f.removeRedundantAttributes&&l(c,k,n,b)||f.removeScriptTypeAttributes&&m(c,k,n)||f.removeStyleLinkTypeAttributes&&o(c,k,n))return"";if(n=t(c,k,n,f,b),f.removeEmptyAttributes&&C(c,k,n))return"";if(void 0!==n&&!f.removeAttributeQuotes||!j(n)){if(!f.preventAttributesEscaping){if(void 0!==f.quoteCharacter)q="'"===f.quoteCharacter?"'":'"';else{var r=(n.match(/'/g)||[]).length,s=(n.match(/"/g)||[]).length;q=s>r?"'":'"'}n='"'===q?n.replace(/"/g,"&#34;"):n.replace(/'/g,"&#39;")}i=q+n+q,g||f.removeTagWhitespace||(i+=" ")}else i=!g||d||/\/$/.test(n)?n+" ":n;return void 0===n||f.collapseBooleanAttributes&&p(k,n)?(h=k,g||(h+=" ")):h=k+a.customAssign+i,a.customOpen+h+a.customClose}function H(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function I(b,c){"object"!=typeof c&&(c={});try{var d=a.RelateUrl;return"undefined"==typeof d&&"function"==typeof require&&(d=require("relateurl")),d&&d.relate?d.relate(b,c):b}catch(e){O(e)}return b}function J(b,c){"object"!=typeof c&&(c={}),c.fromString=!0;var d=c.output||{};d.inline_script=!0,c.output=d;try{var e=a.UglifyJS;if("undefined"==typeof e&&"function"==typeof require&&(e=require("uglify-js")),!e)return b;if(e.minify)return e.minify(b,c).code;if(e.parse){var f=e.parse(b);f.figure_out_scope();var g=e.Compressor(),h=f.transform(g);h.figure_out_scope(),h.compute_char_frequency(),c.mangle!==!1&&h.mangle_names();var i=e.OutputStream(c.output);return h.print(i),i.toString()}return b}catch(j){O(j)}return b}function K(a,b,c){"object"!=typeof b&&(b={}),"undefined"==typeof b.advanced&&(b.advanced=!1);try{var d;if("undefined"!=typeof CleanCSS)d=new CleanCSS(b);else if("function"==typeof require){var e=require("clean-css");d=new e(b)}return c?w(d.minify(v(a)).styles):d.minify(a).styles}catch(f){O(f)}return a}function L(a){var b;do b=Math.random().toString(36).slice(2);while(~a.indexOf(b));return b}function M(a,c){function d(a,b){return E(a)||c.canCollapseWhitespace(a,b)}function i(a,b){return F(a)||c.canTrimWhitespace(a,b)}function j(){for(var a=r.length-1;a>0&&!/^<[^\/!]/.test(r[a]);)a--;r.length=Math.max(0,a)}function k(){for(var a=r.length-1;a>0&&!/^<\//.test(r[a]);)a--;r.length=a}c=c||{};var l=[];a=Q(a),H(c);var m,o,p,q=[],r=[],s="",t="",u=[],v=[],w=[],C="",I="",M=c.lint,R=Date.now(),S=[],T=[];~a.indexOf("<!-- htmlmin:ignore -->")&&(o="<!--!"+L(a)+"-->",a=a.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,function(a,b){return S.push(b),o}));var U=(c.ignoreCustomFragments||[/<%[\s\S]*?%>/,/<\?[\s\S]*?\?>/]).map(function(a){return a.source});if(U.length){var V=new RegExp("\\s*(?:"+U.join("|")+")\\s*","g");a=a.replace(V,function(b){return p||(p=L(a)),T.push(b)," "+p+" "})}new P(a,{html5:"undefined"!=typeof c.html5?c.html5:!0,start:function(a,b,e,f){var g=a.toLowerCase();if("svg"===g){l.push(c);var h={};for(var n in c)h[n]=c[n];h.keepClosingSlash=!0,h.caseSensitive=!0,c=h}a=c.caseSensitive?a:g,t=a,m=a,s="",u=b,c.removeOptionalTags&&(!C||"body"===C&&_(a)||j(),C="",B(I,a)&&k(),I=""),c.collapseWhitespace&&(i(a,b)||v.push(a),d(a,b)||w.push(a));var o="<"+a,p=f&&c.keepClosingSlash;r.push(o),M&&M.testElement(a);for(var q,x=[],y=!0,z=b.length;--z>=0;)M&&M.testAttribute(a,b[z].name.toLowerCase(),b[z].value),q=G(b[z],b,a,p,z,c,y),q&&(y=!1,x.unshift(q));x.length>0?(r.push(" "),r.push.apply(r,x)):c.removeOptionalTags&&Z(a)&&(C=a),r.push(r.pop()+(p?"/":"")+">")},end:function(a,b){var d=a.toLowerCase();if("svg"===d&&(c=l.pop()),a=c.caseSensitive?a:d,c.removeOptionalTags&&(!I||"dt"===I||"thead"===I||"p"===I&&"a"===a||k(),I=$(a)?a:""),c.collapseWhitespace){if(v.length)a===v[v.length-1]&&v.pop();else{var e;r.length>1&&""===r[r.length-1]&&/\s+$/.test(r[r.length-2])?e=r.length-2:r.length>0&&/\s+$/.test(r[r.length-1])&&(e=r.length-1),e>0&&(r[e]=r[e].replace(/\s+$/,function(b){return f(b,"comment","/"+a,c)}))}w.length&&a===w[w.length-1]&&w.pop()}var g=!1;a===t&&(t="",g=""===s),c.removeEmptyElements&&g&&D(a,b)?(j(),C="",I=""):(q.push.apply(q,r),r=["</"+a+">"],m="/"+a,s="")},chars:function(a,d,e){if(d=""===d?"comment":d,e=""===e?"comment":e,c.collapseWhitespace){if(!v.length){if("comment"===d){var g=""===r[r.length-1];if(g&&(d=m),r.length>1&&(g||" "===s.charAt(s.length-1))){var h=r.length-2;r[h]=r[h].replace(/\s+$/,function(b){return a=b+a,""})}}a=d||e?f(a,d,e,c):Q(a)}w.length||(a=d&&e||"html"===e?a:b(a))}("script"===t||"style"===t)&&(c.removeCommentsFromCDATA&&(a=A(a,t)),c.removeCDATASectionsFromCDATA&&(a=y(a)),c.processScripts&&(a=z(a,c,u))),c.minifyJS&&n(t,u)&&(a=J(a,c.minifyJS),";"===a.charAt(a.length-1)&&(a=a.slice(0,-1))),"style"===t&&c.minifyCSS&&(a=K(a,c.minifyCSS)),c.removeOptionalTags&&a&&(("html"===C||"body"===C&&!/^\s/.test(a))&&j(),C="","html"!==I&&"body"!==I&&("head"!==I&&"colgroup"!==I||/^\s/.test(a))||k(),I=""),m=/^\s*$/.test(a)?d:"comment",s+=a,M&&M.testChars(a),r.push(a)},comment:function(a,b){var d=b?"<!":"<!--",e=b?">":"-->";a=c.removeComments?g(a)?d+x(a)+e:h(a,c)?"<!--"+a+"-->":"":d+a+e,c.removeOptionalTags&&a&&(C="",I=""),r.push(a)},doctype:function(a){r.push(c.useShortDoctype?"<!DOCTYPE html>":b(a))},customAttrAssign:c.customAttrAssign,customAttrSurround:c.customAttrSurround}),c.removeOptionalTags&&(C&&j(),I&&"dt"!==I&&"thead"!==I&&k()),q.push.apply(q,r);var W=N(q,c);return p&&(W=W.replace(new RegExp("(\\s*)"+p+"(\\s*)","g"),function(a,b,d){var f=T.shift();return c.collapseWhitespace?e(b+f+d,c.preserveLineBreaks,!0,!0,!0):f})),o&&(W=W.replace(new RegExp(o,"g"),function(){return S.shift()})),O("minified in: "+(Date.now()-R)+"ms"),W}function N(a,b){var c,d=b.maxLineLength;if(d){for(var e,f=[],g="",h=0,i=a.length;i>h;h++)e=a[h],g.length+e.length<d?g+=e:(f.push(g.replace(/^\n/,"")),g=e);f.push(g),c=f.join("\n")}else c=a.join("");return Q(c)}var O,P;O=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?P=a.HTMLParser:"function"==typeof require&&(P=require("./htmlparser").HTMLParser);var Q=function(a){return"string"!=typeof a?a:a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(Q=function(a){return"string"!=typeof a?a:a.trim()});var R=d("a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var"),S=d("comment,img,input"),T=c(["text/javascript","text/ecmascript","text/jscript","application/javascript","application/x-javascript","application/ecmascript"]),U={draggable:["true","false"]},V="!function(){",W="}();",X={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},Y={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},Z=d("html,head,body"),$=d("html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,thead,tbody,tfoot,tr,td,th"),_=d("meta,link,script,style,template"),aa=d("dt,dd"),ba=d("address,article,aside,blockquote,div,dl,fieldset,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,main,nav,ol,p,pre,section,table,ul"),ca=d("rb,rt,rtc,rp"),da=d("rb,rtc,rp"),ea=d("option,optgroup"),fa=d("tbody,tfoot"),ga=d("td,th"),ha=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=M:a.minify=M}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return/^(?:big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|strike)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
\ No newline at end of file
index 77514e8..cb32ca5 100644 (file)
@@ -36,7 +36,7 @@
     };
   }
 
-  function collapseWhitespace(str) {
+  function collapseWhitespaceAll(str) {
     return str ? str.replace(/[\t\n\r ]+/g, ' ') : str;
   }
 
     return createMap(values.split(/,/));
   }
 
-  // array of non-empty element tags that will maintain a single space outside of them
-  var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
-
-  function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
+  function collapseWhitespace(str, preserveLineBreaks, conservativeCollapse, trimLeft, trimRight, collapseAll) {
     var lineBreakBefore = '', lineBreakAfter = '';
 
-    if (options.preserveLineBreaks) {
+    if (preserveLineBreaks) {
       str = str.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/, function() {
         lineBreakBefore = '\n';
         return '';
       });
     }
 
-    if (prevTag && prevTag !== 'img' && prevTag !== 'input' && prevTag !== 'comment'
-      && (prevTag.charAt(0) !== '/' || options.collapseInlineTagWhitespace || !inlineTags(prevTag.substr(1)))) {
-      str = str.replace(/^\s+/, !lineBreakBefore && options.conservativeCollapse ? ' ' : '');
+    if (trimLeft) {
+      str = str.replace(/^\s+/, !lineBreakBefore && conservativeCollapse ? ' ' : '');
     }
 
-    if (nextTag && nextTag !== 'img' && nextTag !== 'input' && nextTag !== 'comment'
-      && (nextTag.charAt(0) === '/' || options.collapseInlineTagWhitespace || !inlineTags(nextTag))) {
-      str = str.replace(/\s+$/, !lineBreakAfter && options.conservativeCollapse ? ' ' : '');
+    if (trimRight) {
+      str = str.replace(/\s+$/, !lineBreakAfter && conservativeCollapse ? ' ' : '');
     }
 
-    if (prevTag && nextTag) {
+    if (collapseAll) {
       // strip non space whitespace then compress spaces to one
-      str = collapseWhitespace(str);
+      str = collapseWhitespaceAll(str);
     }
 
     return lineBreakBefore + str + lineBreakAfter;
   }
 
+  // array of non-empty element tags that will maintain a single space outside of them
+  var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
+  var selfClosingInlineTags = createMapFromString('comment,img,input');
+
+  function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
+    var trimLeft = prevTag && !selfClosingInlineTags(prevTag) && (options.collapseInlineTagWhitespace || prevTag.charAt(0) !== '/' || !inlineTags(prevTag.substr(1)));
+    var trimRight = nextTag && !selfClosingInlineTags(nextTag) && (options.collapseInlineTagWhitespace || nextTag.charAt(0) === '/' || !inlineTags(nextTag));
+    return collapseWhitespace(str, options.preserveLineBreaks, options.conservativeCollapse, trimLeft, trimRight, prevTag && nextTag);
+  }
+
   function isConditionalComment(text) {
     return ((/\[if[^\]]+\]/).test(text) || (/\s*((?:<!)?\[endif\])$/).test(text));
   }
       return attrValue;
     }
     else if (attrName === 'class') {
-      return collapseWhitespace(trimWhitespace(attrValue));
+      return collapseWhitespaceAll(trimWhitespace(attrValue));
     }
     else if (isUriTypeAttribute(attrName, tag)) {
       attrValue = trimWhitespace(attrValue);
       });
     }
 
-    if (options.ignoreCustomFragments) {
-      uidAttr = uniqueId(value);
-      var customFragments = options.ignoreCustomFragments.map(function(re) {
-        return re.source;
-      });
+    var customFragments = (options.ignoreCustomFragments || [
+      /<%[\s\S]*?%>/,
+      /<\?[\s\S]*?\?>/
+    ]).map(function(re) {
+      return re.source;
+    });
+    if (customFragments.length) {
       var reCustomIgnore = new RegExp('\\s*(?:' + customFragments.join('|') + ')\\s*', 'g');
       // temporarily replace custom ignored fragments with unique attributes
       value = value.replace(reCustomIgnore, function(match) {
+        if (!uidAttr) {
+          uidAttr = uniqueId(value);
+        }
         ignoredCustomMarkupChunks.push(match);
         return ' ' + uidAttr + ' ';
       });
             text = prevTag || nextTag ? collapseWhitespaceSmart(text, prevTag, nextTag, options) : trimWhitespace(text);
           }
           if (!stackNoCollapseWhitespace.length) {
-            text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespace(text);
+            text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespaceAll(text);
           }
         }
         if (currentTag === 'script' || currentTag === 'style') {
         buffer.push(text);
       },
       doctype: function(doctype) {
-        buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespace(doctype));
+        buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespaceAll(doctype));
       },
       customAttrAssign: options.customAttrAssign,
       customAttrSurround: options.customAttrSurround
     var str = joinResultSegments(results, options);
 
     if (uidAttr) {
-      str = str.replace(new RegExp('\\s*' + uidAttr + '\\s*', 'g'), function() {
-        return ignoredCustomMarkupChunks.shift();
+      str = str.replace(new RegExp('(\\s*)' + uidAttr + '(\\s*)', 'g'), function(match, prefix, suffix) {
+        var chunk = ignoredCustomMarkupChunks.shift();
+        return options.collapseWhitespace ? collapseWhitespace(prefix + chunk + suffix, options.preserveLineBreaks, true, true, true) : chunk;
       });
     }
     if (uidIgnore) {
index e942f3a..97e44a0 100644 (file)
           }
         }
 
-        // Ignored elements?
-        if ( /^<\?/.test( html ) ) {
-          index = html.indexOf( '?>', 2 );
-          if ( index >= 0 ) {
-            if ( handler.chars ) {
-              handler.chars( html.substring( 0, index + 2 ) );
-            }
-            html = html.substring( index + 2 );
-            prevTag = '';
-            continue;
-          }
-        }
-
-        if ( /^<%/.test( html ) ) {
-          index = html.indexOf( '%>', 2 );
-          if ( index >= 0 ) {
-            if ( handler.chars ) {
-              handler.chars(html.substring( 0, index + 2) );
-            }
-            html = html.substring( index + 2 );
-            prevTag = '';
-            continue;
-          }
-        }
-
         // Doctype:
         if ( (match = doctype.exec( html )) ) {
           if ( handler.doctype ) {
index 6e0cf63..e341cc0 100644 (file)
   // https://github.com/kangax/html-minifier/issues/10
   test('Ignore custom fragments', function() {
 
-    var reFragments = [ /<\?[^\?]+\?>/, /<%[^%]+%>/ ];
+    var reFragments = [ /<\?[^\?]+\?>/, /<%[^%]+%>/, /\{\{[^\}]*\}\}/ ];
 
-    input = 'This is the start. <% ... %>\r\n<%= ... %>\r\n<? ... ?>\r\n<!-- This is the middle, and a comment. -->\r\nNo comment, but middle.\r\n<?= ... ?>\r\n<?php ... ?>\r\n<?xml ... ?>\r\nHello, this is the end!';
-    output = 'This is the start. <% ... %> <%= ... %> <? ... ?> No comment, but middle. <?= ... ?> <?php ... ?> <?xml ... ?> Hello, this is the end!';
+    input = 'This is the start. <% ... %>\r\n<%= ... %>\r\n<? ... ?>\r\n<!-- This is the middle, and a comment. -->\r\nNo comment, but middle.\r\n{{ ... }}\r\n<?php ... ?>\r\n<?xml ... ?>\r\nHello, this is the end!';
+    output = 'This is the start. <% ... %> <%= ... %> <? ... ?> No comment, but middle. {{ ... }} <?php ... ?> <?xml ... ?> Hello, this is the end!';
 
     equal(minify(input, {}), input);
     equal(minify(input, { removeComments: true, collapseWhitespace: true }), output);
+    equal(minify(input, {
+      removeComments: true,
+      collapseWhitespace: true,
+      ignoreCustomFragments: reFragments
+    }), output);
 
-    output = 'This is the start. <% ... %>\r\n<%= ... %>\r\n<? ... ?>\r\nNo comment, but middle.\r\n<?= ... ?>\r\n<?php ... ?>\r\n<?xml ... ?>\r\nHello, this is the end!';
+    output = 'This is the start. <% ... %>\n<%= ... %>\n<? ... ?>\nNo comment, but middle. {{ ... }}\n<?php ... ?>\n<?xml ... ?>\nHello, this is the end!';
 
     equal(minify(input, {
       removeComments: true,
       collapseWhitespace: true,
+      preserveLineBreaks: true
+    }), output);
+
+    output = 'This is the start. <% ... %>\n<%= ... %>\n<? ... ?>\nNo comment, but middle.\n{{ ... }}\n<?php ... ?>\n<?xml ... ?>\nHello, this is the end!';
+
+    equal(minify(input, {
+      removeComments: true,
+      collapseWhitespace: true,
+      preserveLineBreaks: true,
       ignoreCustomFragments: reFragments
     }), output);
 
-    input = '<% if foo? %>\r\n  <div class="bar">\r\n    ...\r\n  </div>\r\n<% end %>';
-    output = '<% if foo? %><div class="bar">...</div><% end %>';
+    input = '{{ if foo? }}\r\n  <div class="bar">\r\n    ...\r\n  </div>\r\n{{ end \n}}';
+    output = '{{ if foo? }}<div class="bar">...</div>{{ end }}';
 
     equal(minify(input, {}), input);
     equal(minify(input, { collapseWhitespace: true }), output);
+    equal(minify(input, { collapseWhitespace: true, ignoreCustomFragments: [] }), output);
 
-    output = '<% if foo? %>\r\n  <div class="bar">...</div>\r\n<% end %>';
+    output = '{{ if foo? }} <div class="bar">...</div> {{ end \n}}';
 
     equal(minify(input, { collapseWhitespace: true, ignoreCustomFragments: reFragments }), output);
 
-    input = '<a class="<% if foo? %>bar<% end %>"></a>';
+    output = '{{ if foo? }}\n<div class="bar">\n...\n</div>\n{{ end \n}}';
+
+    equal(minify(input, {
+      collapseWhitespace: true,
+      preserveLineBreaks: true,
+      ignoreCustomFragments: reFragments
+    }), output);
+
+    input = '<a class="<% if foo? %>bar<% end %> {{ ... }}"></a>';
     equal(minify(input, {}), input);
     equal(minify(input, { ignoreCustomFragments: reFragments }), input);