PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/todo-example/javascriptmvc/steal/build/styles/cssmin.js

http://github.com/addyosmani/todomvc
JavaScript | 236 lines | 159 code | 30 blank | 47 comment | 19 complexity | 447bb9b2c708bbfcfeaea4c1df16c0fb MD5 | raw file
Possible License(s): MIT, Apache-2.0, 0BSD, CC-BY-4.0, BSD-3-Clause
  1. steal(function( steal ) {
  2. /**
  3. * cssmin.js
  4. * Author: Stoyan Stefanov - http://phpied.com/
  5. * This is a JavaScript port of the CSS minification tool
  6. * distributed with YUICompressor, itself a port
  7. * of the cssmin utility by Isaac Schlueter - http://foohack.com/
  8. * Permission is hereby granted to use the JavaScript version under the same
  9. * conditions as the YUICompressor (original YUICompressor note below).
  10. */
  11. /*
  12. * YUI Compressor
  13. * Author: Julien Lecomte - http://www.julienlecomte.net/
  14. * Copyright (c) 2009 Yahoo! Inc. All rights reserved.
  15. * The copyrights embodied in the content of this file are licensed
  16. * by Yahoo! Inc. under the BSD (revised) open source license.
  17. */
  18. var YAHOO = YAHOO || {};
  19. YAHOO.compressor = YAHOO.compressor || {};
  20. YAHOO.compressor.cssmin = function (css, linebreakpos) {
  21. var startIndex = 0,
  22. endIndex = 0,
  23. i = 0, max = 0,
  24. preservedTokens = [],
  25. comments = [],
  26. token = '',
  27. totallen = css.length,
  28. placeholder = '';
  29. // collect all comment blocks...
  30. while ((startIndex = css.indexOf("/*", startIndex)) >= 0) {
  31. endIndex = css.indexOf("*/", startIndex + 2);
  32. if (endIndex < 0) {
  33. endIndex = totallen;
  34. }
  35. token = css.slice(startIndex + 2, endIndex);
  36. comments.push(token);
  37. css = css.slice(0, startIndex + 2) + "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.length - 1) + "___" + css.slice(endIndex);
  38. startIndex += 2;
  39. }
  40. // preserve strings so their content doesn't get accidentally minified
  41. css = css.replace(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/g, function (match) {
  42. var i, max, quote = match.substring(0, 1);
  43. match = match.slice(1, -1);
  44. // maybe the string contains a comment-like substring?
  45. // one, maybe more? put'em back then
  46. if (match.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) {
  47. for (i = 0, max = comments.length; i < max; i = i + 1) {
  48. match = match.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments[i]);
  49. }
  50. }
  51. // minify alpha opacity in filter strings
  52. match = match.replace(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/gi, "alpha(opacity=");
  53. preservedTokens.push(match);
  54. return quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___" + quote;
  55. });
  56. // strings are safe, now wrestle the comments
  57. for (i = 0, max = comments.length; i < max; i = i + 1) {
  58. token = comments[i];
  59. placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___";
  60. // ! in the first position of the comment means preserve
  61. // so push to the preserved tokens keeping the !
  62. if (token.charAt(0) === "!") {
  63. preservedTokens.push(token);
  64. css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
  65. continue;
  66. }
  67. // \ in the last position looks like hack for Mac/IE5
  68. // shorten that to /*\*/ and the next one to /**/
  69. if (token.charAt(token.length - 1) === "\\") {
  70. preservedTokens.push("\\");
  71. css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
  72. i = i + 1; // attn: advancing the loop
  73. preservedTokens.push("");
  74. css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
  75. continue;
  76. }
  77. // keep empty comments after child selectors (IE7 hack)
  78. // e.g. html >/**/ body
  79. if (token.length === 0) {
  80. startIndex = css.indexOf(placeholder);
  81. if (startIndex > 2) {
  82. if (css.charAt(startIndex - 3) === '>') {
  83. preservedTokens.push("");
  84. css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
  85. }
  86. }
  87. }
  88. // in all other cases kill the comment
  89. css = css.replace("/*" + placeholder + "*/", "");
  90. }
  91. // Normalize all whitespace strings to single spaces. Easier to work with that way.
  92. css = css.replace(/\s+/g, " ");
  93. // Remove the spaces before the things that should not have spaces before them.
  94. // But, be careful not to turn "p :link {...}" into "p:link{...}"
  95. // Swap out any pseudo-class colons with the token, and then swap back.
  96. css = css.replace(/(^|\})(([^\{:])+:)+([^\{]*\{)/g, function (m) {
  97. return m.replace(":", "___YUICSSMIN_PSEUDOCLASSCOLON___");
  98. });
  99. css = css.replace(/\s+([!{};:>+\(\)\],])/g, '$1');
  100. css = css.replace(/___YUICSSMIN_PSEUDOCLASSCOLON___/g, ":");
  101. // retain space for special IE6 cases
  102. css = css.replace(/:first-(line|letter)(\{|,)/g, ":first-$1 $2");
  103. // no space after the end of a preserved comment
  104. css = css.replace(/\*\/ /g, '*/');
  105. // If there is a @charset, then only allow one, and push to the top of the file.
  106. css = css.replace(/^(.*)(@charset "[^"]*";)/gi, '$2$1');
  107. css = css.replace(/^(\s*@charset [^;]+;\s*)+/gi, '$1');
  108. // Put the space back in some cases, to support stuff like
  109. // @media screen and (-webkit-min-device-pixel-ratio:0){
  110. css = css.replace(/\band\(/gi, "and (");
  111. // Remove the spaces after the things that should not have spaces after them.
  112. css = css.replace(/([!{}:;>+\(\[,])\s+/g, '$1');
  113. // remove unnecessary semicolons
  114. css = css.replace(/;+\}/g, "}");
  115. // Replace 0(px,em,%) with 0.
  116. css = css.replace(/([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)/gi, "$1$2");
  117. // Replace 0 0 0 0; with 0.
  118. css = css.replace(/:0 0 0 0(;|\})/g, ":0$1");
  119. css = css.replace(/:0 0 0(;|\})/g, ":0$1");
  120. css = css.replace(/:0 0(;|\})/g, ":0$1");
  121. // Replace background-position:0; with background-position:0 0;
  122. // same for transform-origin
  123. css = css.replace(/(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|\})/gi, function(all, prop, tail) {
  124. return prop.toLowerCase() + ":0 0" + tail;
  125. });
  126. // Replace 0.6 to .6, but only when preceded by : or a white-space
  127. css = css.replace(/(:|\s)0+\.(\d+)/g, "$1.$2");
  128. // Shorten colors from rgb(51,102,153) to #336699
  129. // This makes it more likely that it'll get further compressed in the next step.
  130. css = css.replace(/rgb\s*\(\s*([0-9,\s]+)\s*\)/gi, function () {
  131. var i, rgbcolors = arguments[1].split(',');
  132. for (i = 0; i < rgbcolors.length; i = i + 1) {
  133. rgbcolors[i] = parseInt(rgbcolors[i], 10).toString(16);
  134. if (rgbcolors[i].length === 1) {
  135. rgbcolors[i] = '0' + rgbcolors[i];
  136. }
  137. }
  138. return '#' + rgbcolors.join('');
  139. });
  140. // Shorten colors from #AABBCC to #ABC. Note that we want to make sure
  141. // the color is not preceded by either ", " or =. Indeed, the property
  142. // filter: chroma(color="#FFFFFF");
  143. // would become
  144. // filter: chroma(color="#FFF");
  145. // which makes the filter break in IE.
  146. css = css.replace(/([^"'=\s])(\s*)#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])/gi, function () {
  147. var group = arguments;
  148. if (
  149. group[3].toLowerCase() === group[4].toLowerCase() &&
  150. group[5].toLowerCase() === group[6].toLowerCase() &&
  151. group[7].toLowerCase() === group[8].toLowerCase()
  152. ) {
  153. return (group[1] + group[2] + '#' + group[3] + group[5] + group[7]).toLowerCase();
  154. } else {
  155. return group[0].toLowerCase();
  156. }
  157. });
  158. // border: none -> border:0
  159. css = css.replace(/(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|\})/gi, function(all, prop, tail) {
  160. return prop.toLowerCase() + ":0" + tail;
  161. });
  162. // shorter opacity IE filter
  163. css = css.replace(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/gi, "alpha(opacity=");
  164. // Remove empty rules.
  165. css = css.replace(/[^\};\{\/]+\{\}/g, "");
  166. if (linebreakpos >= 0) {
  167. // Some source control tools don't like it when files containing lines longer
  168. // than, say 8000 characters, are checked in. The linebreak option is used in
  169. // that case to split long lines after a specific column.
  170. startIndex = 0;
  171. i = 0;
  172. while (i < css.length) {
  173. i = i + 1;
  174. if (css[i - 1] === '}' && i - startIndex > linebreakpos) {
  175. css = css.slice(0, i) + '\n' + css.slice(i);
  176. startIndex = i;
  177. }
  178. }
  179. }
  180. // Replace multiple semi-colons in a row by a single one
  181. // See SF bug #1980989
  182. css = css.replace(/;;+/g, ";");
  183. // restore preserved comments and strings
  184. for (i = 0, max = preservedTokens.length; i < max; i = i + 1) {
  185. css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens[i]);
  186. }
  187. // Trim the final string (for any leading or trailing white spaces)
  188. css = css.replace(/^\s+|\s+$/g, "");
  189. return css;
  190. };
  191. steal.build.builders.styles.min = function( css ) {
  192. //remove comments & minify
  193. return YAHOO.compressor.cssmin(css);
  194. }
  195. });