Add caseSensitive option; closes #106
authorkangax <kangax@gmail.com>
Fri, 24 Jan 2014 14:37:38 +0000 (09:37 -0500)
committerkangax <kangax@gmail.com>
Fri, 24 Jan 2014 14:37:38 +0000 (09:37 -0500)
README.md
dist/all.js
dist/all.min.js
index.html
master.js
src/htmlminifier.js
tests/minifier.js

index c86a5a1..0176e6a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 [![devDependency Status](https://david-dm.org/kangax/html-minifier/dev-status.png?theme=shields.io)](https://david-dm.org/kangax/html-minifier#info=devDependencies)
 [![NPM version](https://badge.fury.io/js/html-minifier.png)](http://badge.fury.io/js/html-minifier)
 
-[HTMLMinifier](http://kangax.github.io/html-minifier/) is a Javascript-based HTML minifier (duh), with lint-like capabilities.
+[HTMLMinifier](http://kangax.github.io/html-minifier/) is a highly _configurable_, _well-tested_, Javascript-based HTML minifier, with lint-like capabilities.
 
 See [corresponding blog post](http://perfectionkills.com/experimenting-with-html-minifier/) for all the gory details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier/#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier/#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier/#field_testing) and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier/#cost_and_benefits).
 
index 4f7ef2d..76ce44c 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*!
  * HTML Parser By John Resig (ejohn.org)
  * Modified by Juriy "kangax" Zaytsev
  * Original code by Erik Arvidsson, Mozilla Public License
 
   function normalizeAttribute(attr, attrs, tag, options) {
 
-    var attrName = attr.name.toLowerCase(),
+    var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
         attrValue = attr.escaped,
         attrFragment;
 
index c804f82..95a9867 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*!
  * HTML Parser By John Resig (ejohn.org)
  * Modified by Juriy "kangax" Zaytsev
  * Original code by Erik Arvidsson, Mozilla Public License
@@ -22,4 +22,4 @@
  * HTMLtoDOM(htmlString, document);
  * HTMLtoDOM(htmlString, document.body);
  *
- */(function(e){function m(e){var t={},n=e.split(",");for(var r=0;r<n.length;r++)t[n[r]]=!0,t[n[r].toUpperCase()]=!0;return t}var t=/^<([\w:-]+)((?:\s*[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,n=/^<\/([\w:-]+)[^>]*>/,r=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,i=/^<!DOCTYPE [^>]+>/i,s=/<(%|\?)/;endIgnore=/(%|\?)>/;var o=m("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed"),u=m("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"),a=m("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr"),f=m("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),l=m("script,style"),c={},h,p,d,v=e.HTMLParser=function(e,v){function T(e,t,n,i){while(!v.html5&&b.last()&&u[b.last()])N("",b.last());a[t]&&b.last()===t&&N("",t),i=o[t]||!!i,i||b.push(t);if(v.start){var s=[];n.replace(r,function(e,t){var n=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:f[t]?t:"";s.push({name:t,value:n,escaped:n.replace(/(^|[^\\])"/g,'$1\\"')})}),v.start&&v.start(t,s,i)}}function N(e,t){var n;if(!t)n=0;else for(n=b.length-1;n>=0;n--)if(b[n]===t)break;if(n>=0){for(var r=b.length-1;r>=n;r--)v.end&&v.end(b[r]);b.length=n}}var m,g,y,b=[],w=e,E,S;b.last=function(){return this[this.length-1]};while(e){g=!0;if(!b.last()||!l[b.last()]){e.indexOf("<!--")===0?(m=e.indexOf("-->"),m>=0&&(v.comment&&v.comment(e.substring(4,m)),e=e.substring(m+3),g=!1)):e.search(s)===0?(m=e.search(endIgnore),m>=0&&(v.ignore&&v.ignore(e.substring(0,m+2)),e=e.substring(m+2),g=!1)):(y=i.exec(e))?(v.doctype&&v.doctype(y[0]),e=e.substring(y[0].length),g=!1):e.indexOf("</")===0?(y=e.match(n),y&&(e=e.substring(y[0].length),y[0].replace(n,N),E="/"+y[1],g=!1)):e.indexOf("<")===0&&(y=e.match(t),y&&(e=e.substring(y[0].length),y[0].replace(t,T),E=y[1],g=!1));if(g){m=e.indexOf("<");var x=m<0?e:e.substring(0,m);e=m<0?"":e.substring(m),d=e.match(t),d?S=d[1]:(d=e.match(n),d?S="/"+d[1]:S=""),v.chars&&v.chars(x,E,S)}}else h=b.last().toLowerCase(),p=c[h]||(c[h]=new RegExp("([\\s\\S]*?)</"+h+"[^>]*>","i")),e=e.replace(p,function(e,t){return h!=="script"&&h!=="style"&&(t=t.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),v.chars&&v.chars(t),""}),N("",h);if(e===w)throw"Parse Error: "+e;w=e}N()};e.HTMLtoXML=function(e){var t="";return v(e,{start:function(e,n,r){t+="<"+e;for(var i=0;i<n.length;i++)t+=" "+n[i].name+'="'+n[i].escaped+'"';t+=(r?"/":"")+">"},end:function(e){t+="</"+e+">"},chars:function(e){t+=e},comment:function(e){t+="<!--"+e+"-->"},ignore:function(e){t+=e}}),t},e.HTMLtoDOM=function(e,t){var n=m("html,head,body,title"),r={link:"head",base:"head"};t?t=t.ownerDocument||t.getOwnerDocument&&t.getOwnerDocument()||t:typeof DOMDocument!="undefined"?t=new DOMDocument:typeof document!="undefined"&&document.implementation&&document.implementation.createDocument?t=document.implementation.createDocument("","",null):typeof ActiveX!="undefined"&&(t=new ActiveXObject("Msxml.DOMDocument"));var i=[],s=t.documentElement||t.getDocumentElement&&t.getDocumentElement();!s&&t.createElement&&function(){var e=t.createElement("html"),n=t.createElement("head");n.appendChild(t.createElement("title")),e.appendChild(n),e.appendChild(t.createElement("body")),t.appendChild(e)}();if(t.getElementsByTagName)for(var o in n)n[o]=t.getElementsByTagName(o)[0];var u=n.body;return v(e,{start:function(e,s,o){if(n[e]){u=n[e];return}var a=t.createElement(e);for(var f in s)a.setAttribute(s[f].name,s[f].value);r[e]&&typeof n[r[e]]!="boolean"?n[r[e]].appendChild(a):u&&u.appendChild&&u.appendChild(a),o||(i.push(a),u=a)},end:function(){i.length-=1,u=i[i.length-1]},chars:function(e){u.appendChild(t.createTextNode(e))},comment:function(){},ignore:function(){}}),t}})(typeof exports=="undefined"?this:exports),function(e){function i(e){return e.replace(/\s+/g," ")}function s(e,t,n){var r=["a","abbr","acronym","b","bdi","bdo","big","button","cite","code","del","dfn","em","font","i","ins","kbd","mark","q","rt","rp","s","samp","small","span","strike","strong","sub","sup","time","tt","u","var"];return t&&t!=="img"&&(t.substr(0,1)!=="/"||t.substr(0,1)==="/"&&r.indexOf(t.substr(1))===-1)&&(e=e.replace(/^\s+/,"")),n&&n!=="img"&&(n.substr(0,1)==="/"||n.substr(0,1)!=="/"&&r.indexOf(n)===-1)&&(e=e.replace(/\s+$/,"")),t&&n?e.replace(/[\t\n\r]+/g," ").replace(/[ ]+/g," "):e}function o(e){return/\[if[^\]]+\]/.test(e)||/\s*(<!\[endif\])$/.test(e)}function u(e){return/^!/.test(e)}function a(e){return/^on[a-z]+/.test(e)}function f(e){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(e)&&!/\/$/.test(e)&&!/\/$/.test(e)}function l(e,t){for(var n=e.length;n--;)if(e[n].name.toLowerCase()===t)return!0;return!1}function c(e,t,n,i){return n=r(n.toLowerCase()),e==="script"&&t==="language"&&n==="javascript"||e==="form"&&t==="method"&&n==="get"||e==="input"&&t==="type"&&n==="text"||e==="script"&&t==="charset"&&!l(i,"src")||e==="a"&&t==="name"&&l(i,"id")||e==="area"&&t==="shape"&&n==="rect"}function h(e,t,n){return e==="script"&&t==="type"&&r(n.toLowerCase())==="text/javascript"}function p(e,t,n){return(e==="style"||e==="link")&&t==="type"&&r(n.toLowerCase())==="text/css"}function d(e){return/^(?:allowfullscreen|async|autofocus|checked|compact|declare|default|defer|disabled|formnovalidate|hidden|inert|ismap|itemscope|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|readonly|required|reversed|seamless|selected|sortable|truespeed|typemustmatch)$/.test(e)}function v(e,t){return/^(?:a|area|link|base)$/.test(t)&&e==="href"||t==="img"&&/^(?:src|longdesc|usemap)$/.test(e)||t==="object"&&/^(?:classid|codebase|data|usemap)$/.test(e)||t==="q"&&e==="cite"||t==="blockquote"&&e==="cite"||(t==="ins"||t==="del")&&e==="cite"||t==="form"&&e==="action"||t==="input"&&(e==="src"||e==="usemap")||t==="head"&&e==="profile"||t==="script"&&(e==="src"||e==="for")}function m(e,t){return/^(?:a|area|object|button)$/.test(t)&&e==="tabindex"||t==="input"&&(e==="maxlength"||e==="tabindex")||t==="select"&&(e==="size"||e==="tabindex")||t==="textarea"&&/^(?:rows|cols|tabindex)$/.test(e)||t==="colgroup"&&e==="span"||t==="col"&&e==="span"||(t==="th"||t==="td")&&(e==="rowspan"||e==="colspan")}function g(e,t,n){return a(t)?r(n).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""):t==="class"?i(r(n)):v(t,e)||m(t,e)?r(n):t==="style"?r(n).replace(/\s*;\s*$/,""):n}function y(e){return e.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function b(e){return e.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function S(e,t){return e.replace(w[t],"").replace(E[t],"")}function x(e){return/^(?:html|t?body|t?head|tfoot|tr|option)$/.test(e)}function N(e,t,n){var r=/^(["'])?\s*\1$/.test(n);return r?e==="input"&&t==="value"||T.test(t):!1}function C(e){return e!=="textarea"}function k(e){return!/^(?:script|style|pre|textarea)$/.test(e)}function L(e){return!/^(?:pre|textarea)$/.test(e)}function A(e,t,n,r){var i=e.name.toLowerCase(),s=e.escaped,o;if(r.removeRedundantAttributes&&c(n,i,s,t)||r.removeScriptTypeAttributes&&h(n,i,s)||r.removeStyleLinkTypeAttributes&&p(n,i,s))return"";s=g(n,i,s);if(!r.removeAttributeQuotes||!f(s))s='"'+s+'"';return r.removeEmptyAttributes&&N(n,i,s)?"":(r.collapseBooleanAttributes&&d(i)?o=i:o=i+"="+s," "+o)}function O(e){var t=["canCollapseWhitespace","canTrimWhitespace"];for(var n=0,r=t.length;n<r;n++)e[t[n]]||(e[t[n]]=function(){return!1})}function M(e,a){function w(e,t){return k(e)||a.canTrimWhitespace(e,t)}function E(e,t){return L(e)||a.canTrimWhitespace(e,t)}a=a||{},e=r(e),O(a);var f=[],l=[],c="",h="",p=[],d=[],v=[],m=a.lint,g=new Date;n(e,{html5:typeof a.html5!="undefined"?a.html5:!0,start:function(e,t){e=e.toLowerCase(),h=e,c="",p=t,a.collapseWhitespace&&(E(e,t)||d.push(e),w(e,t)||v.push(e)),l.push("<",e),m&&m.testElement(e);for(var n=0,r=t.length;n<r;n++)m&&m.testAttribute(e,t[n].name.toLowerCase(),t[n].escaped),l.push(A(t[n],t,e,a));l.push(">")},end:function(e){a.collapseWhitespace&&(d.length&&e===d[d.length-1]&&d.pop(),v.length&&e===v[v.length-1]&&v.pop());var t=c===""&&e===h;if(a.removeEmptyElements&&t&&C(e)){l.splice(l.lastIndexOf("<"));return}if(a.removeOptionalTags&&x(e))return;l.push("</",e.toLowerCase(),">"),f.push.apply(f,l),l.length=0,c=""},chars:function(e,t,n){if(h==="script"||h==="style")a.removeCommentsFromCDATA&&(e=S(e,h)),a.removeCDATASectionsFromCDATA&&(e=b(e));a.collapseWhitespace&&(d.length||(e=t||n?s(e,t,n):r(e)),v.length||(e=i(e))),c=e,m&&m.testChars(e),l.push(e)},comment:function(e){a.removeComments?o(e)?e="<!--"+y(e)+"-->":u(e)?e="<!--"+e+"-->":e="":e="<!--"+e+"-->",l.push(e)},ignore:function(e){l.push(a.removeIgnored?"":e)},doctype:function(e){l.push(a.useShortDoctype?"<!DOCTYPE html>":i(e))}}),f.push.apply(f,l);var T=f.join("");return t("minified in: "+(new Date-g)+"ms"),T}var t,n;e.console&&e.console.log?t=function(t){e.console.log(t)}:t=function(){},e.HTMLParser?n=e.HTMLParser:typeof require=="function"&&(n=require("./htmlparser").HTMLParser);var r=function(e){return e.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(r=function(e){return e.trim()});var w={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},E={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},T=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");typeof exports!="undefined"?exports.minify=M:e.minify=M}(this),function(e){function t(e){return/^(?:b|i|big|small|hr|blink|marquee)$/.test(e)}function n(e){return/^(?:applet|basefont|center|dir|font|isindex|s|strike|u)$/.test(e)}function r(e){return/^on[a-z]+/.test(e)}function i(e){return"style"===e.toLowerCase()}function s(e,t){return t==="align"&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(e)||t==="alink"&&e==="body"||t==="alt"&&e==="applet"||t==="archive"&&e==="applet"||t==="background"&&e==="body"||t==="bgcolor"&&/^(?:table|t[rdh]|body)$/.test(e)||t==="border"&&/^(?:img|object)$/.test(e)||t==="clear"&&e==="br"||t==="code"&&e==="applet"||t==="codebase"&&e==="applet"||t==="color"&&/^(?:base(?:font)?)$/.test(e)||t==="compact"&&/^(?:dir|[dou]l|menu)$/.test(e)||t==="face"&&/^base(?:font)?$/.test(e)||t==="height"&&/^(?:t[dh]|applet)$/.test(e)||t==="hspace"&&/^(?:applet|img|object)$/.test(e)||t==="language"&&e==="script"||t==="link"&&e==="body"||t==="name"&&e==="applet"||t==="noshade"&&e==="hr"||t==="nowrap"&&/^t[dh]$/.test(e)||t==="object"&&e==="applet"||t==="prompt"&&e==="isindex"||t==="size"&&/^(?:hr|font|basefont)$/.test(e)||t==="start"&&e==="ol"||t==="text"&&e==="body"||t==="type"&&/^(?:li|ol|ul)$/.test(e)||t==="value"&&e==="li"||t==="version"&&e==="html"||t==="vlink"&&e==="body"||t==="vspace"&&/^(?:applet|img|object)$/.test(e)||t==="width"&&/^(?:hr|td|th|applet|pre)$/.test(e)}function o(e,t){return e==="href"&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(t)}function u(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}u.prototype.testElement=function(e){n(e)?this.log.push('<li>Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+e+"&gt;</code></strong> element</li>"):t(e)?this.log.push('<li>Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+e+"&gt;</code></strong> element</li>"):this.checkRepeatingElement(e)},u.prototype.checkRepeatingElement=function(e){e==="br"&&this._lastElement==="br"?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=e},u.prototype._reportRepeatingElement=function(){this.log.push("<li>Found <code>&lt;br></code> sequence. Try replacing it with styling.</li>")},u.prototype.testAttribute=function(e,t,n){r(t)?this.log.push('<li>Found <span class="event-attribute">event attribute</span> (<strong>',t,"</strong>) on <strong><code>&lt;"+e+"&gt;</code></strong> element</li>"):s(e,t)?this.log.push('<li>Found <span class="deprecated-attribute">deprecated</span> <strong>'+t+"</strong> attribute on <strong><code>&lt;",e,"&gt;</code></strong> element</li>"):i(t)?this.log.push('<li>Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;',e,"&gt;</code></strong> element</li>"):o(t,n)&&this.log.push('<li>Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;',e,"&gt;</code></strong> element)</li>")},u.prototype.testChars=function(e){this._lastElement="",/(&nbsp;\s*){2,}/.test(e)&&this.log.push("<li>Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.</li>")},u.prototype.test=function(e,t,n){this.testElement(e),this.testAttribute(e,t,n)},u.prototype.populate=function(e){this._isElementRepeated&&this._reportRepeatingElement();var t;this.log.length&&e&&(t="<ol>"+this.log.join("")+"</ol>",e.innerHTML=t)},e.HTMLLint=u}(typeof exports=="undefined"?this:exports);
\ No newline at end of file
+ */(function(e){function m(e){var t={},n=e.split(",");for(var r=0;r<n.length;r++)t[n[r]]=!0,t[n[r].toUpperCase()]=!0;return t}var t=/^<([\w:-]+)((?:\s*[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,n=/^<\/([\w:-]+)[^>]*>/,r=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,i=/^<!DOCTYPE [^>]+>/i,s=/<(%|\?)/;endIgnore=/(%|\?)>/;var o=m("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed"),u=m("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"),a=m("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr"),f=m("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),l=m("script,style"),c={},h,p,d,v=e.HTMLParser=function(e,v){function T(e,t,n,i){while(!v.html5&&b.last()&&u[b.last()])N("",b.last());a[t]&&b.last()===t&&N("",t),i=o[t]||!!i,i||b.push(t);if(v.start){var s=[];n.replace(r,function(e,t){var n=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:f[t]?t:"";s.push({name:t,value:n,escaped:n.replace(/(^|[^\\])"/g,'$1\\"')})}),v.start&&v.start(t,s,i)}}function N(e,t){var n;if(!t)n=0;else for(n=b.length-1;n>=0;n--)if(b[n]===t)break;if(n>=0){for(var r=b.length-1;r>=n;r--)v.end&&v.end(b[r]);b.length=n}}var m,g,y,b=[],w=e,E,S;b.last=function(){return this[this.length-1]};while(e){g=!0;if(!b.last()||!l[b.last()]){e.indexOf("<!--")===0?(m=e.indexOf("-->"),m>=0&&(v.comment&&v.comment(e.substring(4,m)),e=e.substring(m+3),g=!1)):e.search(s)===0?(m=e.search(endIgnore),m>=0&&(v.ignore&&v.ignore(e.substring(0,m+2)),e=e.substring(m+2),g=!1)):(y=i.exec(e))?(v.doctype&&v.doctype(y[0]),e=e.substring(y[0].length),g=!1):e.indexOf("</")===0?(y=e.match(n),y&&(e=e.substring(y[0].length),y[0].replace(n,N),E="/"+y[1],g=!1)):e.indexOf("<")===0&&(y=e.match(t),y&&(e=e.substring(y[0].length),y[0].replace(t,T),E=y[1],g=!1));if(g){m=e.indexOf("<");var x=m<0?e:e.substring(0,m);e=m<0?"":e.substring(m),d=e.match(t),d?S=d[1]:(d=e.match(n),d?S="/"+d[1]:S=""),v.chars&&v.chars(x,E,S)}}else h=b.last().toLowerCase(),p=c[h]||(c[h]=new RegExp("([\\s\\S]*?)</"+h+"[^>]*>","i")),e=e.replace(p,function(e,t){return h!=="script"&&h!=="style"&&(t=t.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),v.chars&&v.chars(t),""}),N("",h);if(e===w)throw"Parse Error: "+e;w=e}N()};e.HTMLtoXML=function(e){var t="";return v(e,{start:function(e,n,r){t+="<"+e;for(var i=0;i<n.length;i++)t+=" "+n[i].name+'="'+n[i].escaped+'"';t+=(r?"/":"")+">"},end:function(e){t+="</"+e+">"},chars:function(e){t+=e},comment:function(e){t+="<!--"+e+"-->"},ignore:function(e){t+=e}}),t},e.HTMLtoDOM=function(e,t){var n=m("html,head,body,title"),r={link:"head",base:"head"};t?t=t.ownerDocument||t.getOwnerDocument&&t.getOwnerDocument()||t:typeof DOMDocument!="undefined"?t=new DOMDocument:typeof document!="undefined"&&document.implementation&&document.implementation.createDocument?t=document.implementation.createDocument("","",null):typeof ActiveX!="undefined"&&(t=new ActiveXObject("Msxml.DOMDocument"));var i=[],s=t.documentElement||t.getDocumentElement&&t.getDocumentElement();!s&&t.createElement&&function(){var e=t.createElement("html"),n=t.createElement("head");n.appendChild(t.createElement("title")),e.appendChild(n),e.appendChild(t.createElement("body")),t.appendChild(e)}();if(t.getElementsByTagName)for(var o in n)n[o]=t.getElementsByTagName(o)[0];var u=n.body;return v(e,{start:function(e,s,o){if(n[e]){u=n[e];return}var a=t.createElement(e);for(var f in s)a.setAttribute(s[f].name,s[f].value);r[e]&&typeof n[r[e]]!="boolean"?n[r[e]].appendChild(a):u&&u.appendChild&&u.appendChild(a),o||(i.push(a),u=a)},end:function(){i.length-=1,u=i[i.length-1]},chars:function(e){u.appendChild(t.createTextNode(e))},comment:function(){},ignore:function(){}}),t}})(typeof exports=="undefined"?this:exports),function(e){function i(e){return e.replace(/\s+/g," ")}function s(e,t,n){var r=["a","abbr","acronym","b","bdi","bdo","big","button","cite","code","del","dfn","em","font","i","ins","kbd","mark","q","rt","rp","s","samp","small","span","strike","strong","sub","sup","time","tt","u","var"];return t&&t!=="img"&&(t.substr(0,1)!=="/"||t.substr(0,1)==="/"&&r.indexOf(t.substr(1))===-1)&&(e=e.replace(/^\s+/,"")),n&&n!=="img"&&(n.substr(0,1)==="/"||n.substr(0,1)!=="/"&&r.indexOf(n)===-1)&&(e=e.replace(/\s+$/,"")),t&&n?e.replace(/[\t\n\r]+/g," ").replace(/[ ]+/g," "):e}function o(e){return/\[if[^\]]+\]/.test(e)||/\s*(<!\[endif\])$/.test(e)}function u(e){return/^!/.test(e)}function a(e){return/^on[a-z]+/.test(e)}function f(e){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(e)&&!/\/$/.test(e)&&!/\/$/.test(e)}function l(e,t){for(var n=e.length;n--;)if(e[n].name.toLowerCase()===t)return!0;return!1}function c(e,t,n,i){return n=r(n.toLowerCase()),e==="script"&&t==="language"&&n==="javascript"||e==="form"&&t==="method"&&n==="get"||e==="input"&&t==="type"&&n==="text"||e==="script"&&t==="charset"&&!l(i,"src")||e==="a"&&t==="name"&&l(i,"id")||e==="area"&&t==="shape"&&n==="rect"}function h(e,t,n){return e==="script"&&t==="type"&&r(n.toLowerCase())==="text/javascript"}function p(e,t,n){return(e==="style"||e==="link")&&t==="type"&&r(n.toLowerCase())==="text/css"}function d(e){return/^(?:allowfullscreen|async|autofocus|checked|compact|declare|default|defer|disabled|formnovalidate|hidden|inert|ismap|itemscope|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|readonly|required|reversed|seamless|selected|sortable|truespeed|typemustmatch)$/.test(e)}function v(e,t){return/^(?:a|area|link|base)$/.test(t)&&e==="href"||t==="img"&&/^(?:src|longdesc|usemap)$/.test(e)||t==="object"&&/^(?:classid|codebase|data|usemap)$/.test(e)||t==="q"&&e==="cite"||t==="blockquote"&&e==="cite"||(t==="ins"||t==="del")&&e==="cite"||t==="form"&&e==="action"||t==="input"&&(e==="src"||e==="usemap")||t==="head"&&e==="profile"||t==="script"&&(e==="src"||e==="for")}function m(e,t){return/^(?:a|area|object|button)$/.test(t)&&e==="tabindex"||t==="input"&&(e==="maxlength"||e==="tabindex")||t==="select"&&(e==="size"||e==="tabindex")||t==="textarea"&&/^(?:rows|cols|tabindex)$/.test(e)||t==="colgroup"&&e==="span"||t==="col"&&e==="span"||(t==="th"||t==="td")&&(e==="rowspan"||e==="colspan")}function g(e,t,n){return a(t)?r(n).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""):t==="class"?i(r(n)):v(t,e)||m(t,e)?r(n):t==="style"?r(n).replace(/\s*;\s*$/,""):n}function y(e){return e.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function b(e){return e.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function S(e,t){return e.replace(w[t],"").replace(E[t],"")}function x(e){return/^(?:html|t?body|t?head|tfoot|tr|option)$/.test(e)}function N(e,t,n){var r=/^(["'])?\s*\1$/.test(n);return r?e==="input"&&t==="value"||T.test(t):!1}function C(e){return e!=="textarea"}function k(e){return!/^(?:script|style|pre|textarea)$/.test(e)}function L(e){return!/^(?:pre|textarea)$/.test(e)}function A(e,t,n,r){var i=r.caseSensitive?e.name:e.name.toLowerCase(),s=e.escaped,o;if(r.removeRedundantAttributes&&c(n,i,s,t)||r.removeScriptTypeAttributes&&h(n,i,s)||r.removeStyleLinkTypeAttributes&&p(n,i,s))return"";s=g(n,i,s);if(!r.removeAttributeQuotes||!f(s))s='"'+s+'"';return r.removeEmptyAttributes&&N(n,i,s)?"":(r.collapseBooleanAttributes&&d(i)?o=i:o=i+"="+s," "+o)}function O(e){var t=["canCollapseWhitespace","canTrimWhitespace"];for(var n=0,r=t.length;n<r;n++)e[t[n]]||(e[t[n]]=function(){return!1})}function M(e,a){function w(e,t){return k(e)||a.canTrimWhitespace(e,t)}function E(e,t){return L(e)||a.canTrimWhitespace(e,t)}a=a||{},e=r(e),O(a);var f=[],l=[],c="",h="",p=[],d=[],v=[],m=a.lint,g=new Date;n(e,{html5:typeof a.html5!="undefined"?a.html5:!0,start:function(e,t){e=e.toLowerCase(),h=e,c="",p=t,a.collapseWhitespace&&(E(e,t)||d.push(e),w(e,t)||v.push(e)),l.push("<",e),m&&m.testElement(e);for(var n=0,r=t.length;n<r;n++)m&&m.testAttribute(e,t[n].name.toLowerCase(),t[n].escaped),l.push(A(t[n],t,e,a));l.push(">")},end:function(e){a.collapseWhitespace&&(d.length&&e===d[d.length-1]&&d.pop(),v.length&&e===v[v.length-1]&&v.pop());var t=c===""&&e===h;if(a.removeEmptyElements&&t&&C(e)){l.splice(l.lastIndexOf("<"));return}if(a.removeOptionalTags&&x(e))return;l.push("</",e.toLowerCase(),">"),f.push.apply(f,l),l.length=0,c=""},chars:function(e,t,n){if(h==="script"||h==="style")a.removeCommentsFromCDATA&&(e=S(e,h)),a.removeCDATASectionsFromCDATA&&(e=b(e));a.collapseWhitespace&&(d.length||(e=t||n?s(e,t,n):r(e)),v.length||(e=i(e))),c=e,m&&m.testChars(e),l.push(e)},comment:function(e){a.removeComments?o(e)?e="<!--"+y(e)+"-->":u(e)?e="<!--"+e+"-->":e="":e="<!--"+e+"-->",l.push(e)},ignore:function(e){l.push(a.removeIgnored?"":e)},doctype:function(e){l.push(a.useShortDoctype?"<!DOCTYPE html>":i(e))}}),f.push.apply(f,l);var T=f.join("");return t("minified in: "+(new Date-g)+"ms"),T}var t,n;e.console&&e.console.log?t=function(t){e.console.log(t)}:t=function(){},e.HTMLParser?n=e.HTMLParser:typeof require=="function"&&(n=require("./htmlparser").HTMLParser);var r=function(e){return e.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(r=function(e){return e.trim()});var w={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},E={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},T=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");typeof exports!="undefined"?exports.minify=M:e.minify=M}(this),function(e){function t(e){return/^(?:b|i|big|small|hr|blink|marquee)$/.test(e)}function n(e){return/^(?:applet|basefont|center|dir|font|isindex|s|strike|u)$/.test(e)}function r(e){return/^on[a-z]+/.test(e)}function i(e){return"style"===e.toLowerCase()}function s(e,t){return t==="align"&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(e)||t==="alink"&&e==="body"||t==="alt"&&e==="applet"||t==="archive"&&e==="applet"||t==="background"&&e==="body"||t==="bgcolor"&&/^(?:table|t[rdh]|body)$/.test(e)||t==="border"&&/^(?:img|object)$/.test(e)||t==="clear"&&e==="br"||t==="code"&&e==="applet"||t==="codebase"&&e==="applet"||t==="color"&&/^(?:base(?:font)?)$/.test(e)||t==="compact"&&/^(?:dir|[dou]l|menu)$/.test(e)||t==="face"&&/^base(?:font)?$/.test(e)||t==="height"&&/^(?:t[dh]|applet)$/.test(e)||t==="hspace"&&/^(?:applet|img|object)$/.test(e)||t==="language"&&e==="script"||t==="link"&&e==="body"||t==="name"&&e==="applet"||t==="noshade"&&e==="hr"||t==="nowrap"&&/^t[dh]$/.test(e)||t==="object"&&e==="applet"||t==="prompt"&&e==="isindex"||t==="size"&&/^(?:hr|font|basefont)$/.test(e)||t==="start"&&e==="ol"||t==="text"&&e==="body"||t==="type"&&/^(?:li|ol|ul)$/.test(e)||t==="value"&&e==="li"||t==="version"&&e==="html"||t==="vlink"&&e==="body"||t==="vspace"&&/^(?:applet|img|object)$/.test(e)||t==="width"&&/^(?:hr|td|th|applet|pre)$/.test(e)}function o(e,t){return e==="href"&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(t)}function u(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}u.prototype.testElement=function(e){n(e)?this.log.push('<li>Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+e+"&gt;</code></strong> element</li>"):t(e)?this.log.push('<li>Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+e+"&gt;</code></strong> element</li>"):this.checkRepeatingElement(e)},u.prototype.checkRepeatingElement=function(e){e==="br"&&this._lastElement==="br"?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=e},u.prototype._reportRepeatingElement=function(){this.log.push("<li>Found <code>&lt;br></code> sequence. Try replacing it with styling.</li>")},u.prototype.testAttribute=function(e,t,n){r(t)?this.log.push('<li>Found <span class="event-attribute">event attribute</span> (<strong>',t,"</strong>) on <strong><code>&lt;"+e+"&gt;</code></strong> element</li>"):s(e,t)?this.log.push('<li>Found <span class="deprecated-attribute">deprecated</span> <strong>'+t+"</strong> attribute on <strong><code>&lt;",e,"&gt;</code></strong> element</li>"):i(t)?this.log.push('<li>Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;',e,"&gt;</code></strong> element</li>"):o(t,n)&&this.log.push('<li>Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;',e,"&gt;</code></strong> element)</li>")},u.prototype.testChars=function(e){this._lastElement="",/(&nbsp;\s*){2,}/.test(e)&&this.log.push("<li>Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.</li>")},u.prototype.test=function(e,t,n){this.testElement(e),this.testAttribute(e,t,n)},u.prototype.populate=function(e){this._isElementRepeated&&this._reportRepeatingElement();var t;this.log.length&&e&&(t="<ol>"+this.log.join("")+"</ol>",e.innerHTML=t)},e.HTMLLint=u}(typeof exports=="undefined"?this:exports);
\ No newline at end of file
index 1156d0a..a348cfd 100644 (file)
             <button type="button" id="minify-btn">Minify</button>
           </p>
           <textarea rows="8" cols="40" id="output" readonly></textarea>
+
+          <p id="stats"></p>
+          <div id="lint-report">
+            LINT REPORT:
+            <div id="report"></div>
+          </div>
         </div>
         <div id="options">
           <ul>
                 </span>
               </label>
             </li>
+            <li>
+              <input type="checkbox" id="case-sensitive">
+              <label for="case-sensitive">
+                Case-sensitive attributes
+                <br>
+                <span class="quiet short">
+                  Useful when minifying SVG
+                </span>
+              </label>
+            </li>
             <li>
               <input type="checkbox" id="use-htmllint" checked>
               <label for="use-htmllint">
           </div>
         </div>
       </div>
-      <p id="stats"></p>
-      <div id="lint-report">
-        LINT REPORT:
-        <div id="report"></div>
-      </div>
       <p class="quiet" style="font-style:italic;">
         HTMLMinifier is made by <a href="http://perfectionkills.com/">kangax</a>,
         using tweaked version of HTML parser by <a href="http://ejohn.org/">John Resig</a>
index 364890b..419233c 100644 (file)
--- a/master.js
+++ b/master.js
@@ -1,13 +1,13 @@
 (function(){
-  
+
   function byId(id) {
     return document.getElementById(id);
   }
-  
+
   function escapeHTML(str) {
     return (str + '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
   }
-  
+
   function getOptions() {
     return {
       removeIgnored:                  byId('remove-ignored').checked,
@@ -16,7 +16,7 @@
       removeCDATASectionsFromCDATA:   byId('remove-cdata-sections-from-cdata').checked,
       collapseWhitespace:             byId('collapse-whitespace').checked,
       collapseBooleanAttributes:      byId('collapse-boolean-attributes').checked,
-      removeAttributeQuotes:          byId('remove-attribute-quotes').checked,  
+      removeAttributeQuotes:          byId('remove-attribute-quotes').checked,
       removeRedundantAttributes:      byId('remove-redundant-attributes').checked,
       useShortDoctype:                byId('use-short-doctype').checked,
       removeEmptyAttributes:          byId('remove-empty-attributes').checked,
       removeOptionalTags:             byId('remove-optional-tags').checked,
       removeScriptTypeAttributes:     byId('remove-script-type-attributes').checked,
       removeStyleLinkTypeAttributes:  byId('remove-style-link-type-attributes').checked,
+      caseSensitive:                  byId('case-sensitive').checked,
       lint:                           byId('use-htmllint').checked ? new HTMLLint() : null
     };
   }
-  
+
   function commify(str) {
     return String(str)
       .split('').reverse().join('')
       .replace(/(...)(?!$)/g, '$1,')
       .split('').reverse().join('');
   }
-  
+
   byId('minify-btn').onclick = function() {
     try {
       var options = getOptions(),
 
       byId('output').value = minifiedValue;
 
-      byId('stats').innerHTML = 
+      byId('stats').innerHTML =
         '<span class="success">' +
           'Original size: <strong>' + commify(originalValue.length) + '</strong>' +
           '. Minified size: <strong>' + commify(minifiedValue.length) + '</strong>' +
           '. Savings: <strong>' + commify(diff) + ' (' + savings + '%)</strong>.' +
         '</span>';
-      
+
       if (lint) {
         lint.populate(byId('report'));
       }
       byId('stats').innerHTML = '<span class="failure">' + escapeHTML(err) + '</span>';
     }
   };
-  
+
   function setCheckedAttrOnCheckboxes(attrValue) {
     var checkboxes = byId('options').getElementsByTagName('input');
     for (var i = checkboxes.length; i--; ) {
       checkboxes[i].checked = attrValue;
     }
   }
-  
+
   byId('select-all').onclick = function() {
     setCheckedAttrOnCheckboxes(true);
     return false;
   };
-  
+
   byId('select-none').onclick = function() {
     setCheckedAttrOnCheckboxes(false);
     return false;
   };
-  
+
   byId('select-safe').onclick = function() {
     setCheckedAttrOnCheckboxes(true);
     var inputEls = byId('options').getElementsByTagName('input');
@@ -87,7 +88,7 @@
     inputEls[11].checked = false;
     return false;
   };
-  
+
 })();
 
 var _gaq = _gaq || [];
@@ -95,9 +96,9 @@ _gaq.push(['_setAccount', 'UA-1128111-22']);
 _gaq.push(['_trackPageview']);
 
 (function() {
-  var ga = document.createElement('script'); 
-  ga.type = 'text/javascript'; 
+  var ga = document.createElement('script');
+  ga.type = 'text/javascript';
   ga.async = true;
   ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
   document.getElementsByTagName('head')[0].appendChild(ga);
-})();
\ No newline at end of file
+})();
index 7b05ccb..c8ec9eb 100644 (file)
 
   function normalizeAttribute(attr, attrs, tag, options) {
 
-    var attrName = attr.name.toLowerCase(),
+    var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
         attrValue = attr.escaped,
         attrFragment;
 
index ea5dc3c..9f466a0 100644 (file)
     equal(minify(input, { collapseWhitespace: true, removeAttributeQuotes: true }), output);
   });
 
+  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"></svg>';
+
+    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"></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"></svg>';
+
+    equal(minify(input), caseInSensitiveOutput);
+    equal(minify(input, { caseSensitive: true }), caseSensitiveOutput);
+  });
+
 })(typeof exports === 'undefined' ? window : exports);