multi_css 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. data/vendor/cssminify/.gitignore +9 -0
  2. data/vendor/cssminify/.travis.yml +7 -0
  3. data/vendor/cssminify/CHANGES.md +12 -0
  4. data/vendor/cssminify/Gemfile +4 -0
  5. data/vendor/cssminify/LICENSE.md +22 -0
  6. data/vendor/cssminify/README.md +64 -0
  7. data/vendor/cssminify/cssminify.gemspec +30 -0
  8. data/vendor/cssminify/lib/cssminify.rb +34 -0
  9. data/vendor/cssminify/lib/cssminify/cssmin.rb +383 -0
  10. data/vendor/cssminify/lib/cssminify/version.rb +5 -0
  11. data/vendor/cssminify/spec/cssminify_spec.rb +257 -0
  12. data/vendor/cssminify/spec/sample.css +100 -0
  13. data/vendor/cssminify/spec/spec_helper.rb +4 -0
  14. data/vendor/cssminify/spec/tests/background-position.css +2 -0
  15. data/vendor/cssminify/spec/tests/background-position.css.min +1 -0
  16. data/vendor/cssminify/spec/tests/border-none.css +5 -0
  17. data/vendor/cssminify/spec/tests/border-none.css.min +1 -0
  18. data/vendor/cssminify/spec/tests/box-model-hack.css +9 -0
  19. data/vendor/cssminify/spec/tests/box-model-hack.css.min +1 -0
  20. data/vendor/cssminify/spec/tests/bug2527974.css +10 -0
  21. data/vendor/cssminify/spec/tests/bug2527974.css.min +1 -0
  22. data/vendor/cssminify/spec/tests/bug2527991.css +19 -0
  23. data/vendor/cssminify/spec/tests/bug2527991.css.min +1 -0
  24. data/vendor/cssminify/spec/tests/bug2527998.css +4 -0
  25. data/vendor/cssminify/spec/tests/bug2527998.css.min +1 -0
  26. data/vendor/cssminify/spec/tests/bug2528034.css +5 -0
  27. data/vendor/cssminify/spec/tests/bug2528034.css.min +1 -0
  28. data/vendor/cssminify/spec/tests/bug2528093.css +3 -0
  29. data/vendor/cssminify/spec/tests/bug2528093.css.min +1 -0
  30. data/vendor/cssminify/spec/tests/charset-media.css +9 -0
  31. data/vendor/cssminify/spec/tests/charset-media.css.min +1 -0
  32. data/vendor/cssminify/spec/tests/color-simple.css +8 -0
  33. data/vendor/cssminify/spec/tests/color-simple.css.min +1 -0
  34. data/vendor/cssminify/spec/tests/color.css +46 -0
  35. data/vendor/cssminify/spec/tests/color.css.min +1 -0
  36. data/vendor/cssminify/spec/tests/comment.css +3 -0
  37. data/vendor/cssminify/spec/tests/comment.css.min +1 -0
  38. data/vendor/cssminify/spec/tests/concat-charset.css +15 -0
  39. data/vendor/cssminify/spec/tests/concat-charset.css.min +1 -0
  40. data/vendor/cssminify/spec/tests/dataurl-base64-doublequotes.css +23 -0
  41. data/vendor/cssminify/spec/tests/dataurl-base64-doublequotes.css.min +1 -0
  42. data/vendor/cssminify/spec/tests/dataurl-base64-eof.css +10 -0
  43. data/vendor/cssminify/spec/tests/dataurl-base64-eof.css.min +1 -0
  44. data/vendor/cssminify/spec/tests/dataurl-base64-linebreakindata.css +34 -0
  45. data/vendor/cssminify/spec/tests/dataurl-base64-linebreakindata.css.min +1 -0
  46. data/vendor/cssminify/spec/tests/dataurl-base64-noquotes.css +26 -0
  47. data/vendor/cssminify/spec/tests/dataurl-base64-noquotes.css.min +1 -0
  48. data/vendor/cssminify/spec/tests/dataurl-base64-singlequotes.css +23 -0
  49. data/vendor/cssminify/spec/tests/dataurl-base64-singlequotes.css.min +1 -0
  50. data/vendor/cssminify/spec/tests/dataurl-base64-twourls.css +27 -0
  51. data/vendor/cssminify/spec/tests/dataurl-base64-twourls.css.min +1 -0
  52. data/vendor/cssminify/spec/tests/dataurl-dbquote-font.css +30 -0
  53. data/vendor/cssminify/spec/tests/dataurl-dbquote-font.css.min +5 -0
  54. data/vendor/cssminify/spec/tests/dataurl-nonbase64-doublequotes.css +13 -0
  55. data/vendor/cssminify/spec/tests/dataurl-nonbase64-doublequotes.css.min +1 -0
  56. data/vendor/cssminify/spec/tests/dataurl-nonbase64-noquotes.css +11 -0
  57. data/vendor/cssminify/spec/tests/dataurl-nonbase64-noquotes.css.min +1 -0
  58. data/vendor/cssminify/spec/tests/dataurl-nonbase64-singlequotes.css +15 -0
  59. data/vendor/cssminify/spec/tests/dataurl-nonbase64-singlequotes.css.min +2 -0
  60. data/vendor/cssminify/spec/tests/dataurl-noquote-multiline-font.css +31 -0
  61. data/vendor/cssminify/spec/tests/dataurl-noquote-multiline-font.css.min +3 -0
  62. data/vendor/cssminify/spec/tests/dataurl-realdata-doublequotes.css +90 -0
  63. data/vendor/cssminify/spec/tests/dataurl-realdata-doublequotes.css.min +1 -0
  64. data/vendor/cssminify/spec/tests/dataurl-realdata-noquotes.css +90 -0
  65. data/vendor/cssminify/spec/tests/dataurl-realdata-noquotes.css.min +1 -0
  66. data/vendor/cssminify/spec/tests/dataurl-realdata-singlequotes.css +90 -0
  67. data/vendor/cssminify/spec/tests/dataurl-realdata-singlequotes.css.min +1 -0
  68. data/vendor/cssminify/spec/tests/dataurl-realdata-yuiapp.css +106 -0
  69. data/vendor/cssminify/spec/tests/dataurl-realdata-yuiapp.css.min +1 -0
  70. data/vendor/cssminify/spec/tests/dataurl-singlequote-font.css +30 -0
  71. data/vendor/cssminify/spec/tests/dataurl-singlequote-font.css.min +3 -0
  72. data/vendor/cssminify/spec/tests/decimals.css +3 -0
  73. data/vendor/cssminify/spec/tests/decimals.css.min +1 -0
  74. data/vendor/cssminify/spec/tests/dollar-header.css +7 -0
  75. data/vendor/cssminify/spec/tests/dollar-header.css.min +3 -0
  76. data/vendor/cssminify/spec/tests/font-face.css +6 -0
  77. data/vendor/cssminify/spec/tests/font-face.css.min +1 -0
  78. data/vendor/cssminify/spec/tests/ie5mac.css +5 -0
  79. data/vendor/cssminify/spec/tests/ie5mac.css.min +1 -0
  80. data/vendor/cssminify/spec/tests/media-empty-class.css +16 -0
  81. data/vendor/cssminify/spec/tests/media-empty-class.css.min +1 -0
  82. data/vendor/cssminify/spec/tests/media-multi.css +3 -0
  83. data/vendor/cssminify/spec/tests/media-multi.css.min +1 -0
  84. data/vendor/cssminify/spec/tests/media-test.css +3 -0
  85. data/vendor/cssminify/spec/tests/media-test.css.min +1 -0
  86. data/vendor/cssminify/spec/tests/opacity-filter.css +14 -0
  87. data/vendor/cssminify/spec/tests/opacity-filter.css.min +1 -0
  88. data/vendor/cssminify/spec/tests/preserve-case.css +15 -0
  89. data/vendor/cssminify/spec/tests/preserve-case.css.min +1 -0
  90. data/vendor/cssminify/spec/tests/preserve-new-line.css +6 -0
  91. data/vendor/cssminify/spec/tests/preserve-new-line.css.min +3 -0
  92. data/vendor/cssminify/spec/tests/preserve-strings.css +7 -0
  93. data/vendor/cssminify/spec/tests/preserve-strings.css.min +1 -0
  94. data/vendor/cssminify/spec/tests/pseudo-first.css +16 -0
  95. data/vendor/cssminify/spec/tests/pseudo-first.css.min +1 -0
  96. data/vendor/cssminify/spec/tests/pseudo.css +4 -0
  97. data/vendor/cssminify/spec/tests/pseudo.css.min +1 -0
  98. data/vendor/cssminify/spec/tests/special-comments.css +13 -0
  99. data/vendor/cssminify/spec/tests/special-comments.css.min +9 -0
  100. data/vendor/cssminify/spec/tests/star-underscore-hacks.css +5 -0
  101. data/vendor/cssminify/spec/tests/star-underscore-hacks.css.min +1 -0
  102. data/vendor/cssminify/spec/tests/string-in-comment.css +8 -0
  103. data/vendor/cssminify/spec/tests/string-in-comment.css.min +1 -0
  104. data/vendor/cssminify/spec/tests/webkit-transform.css +2 -0
  105. data/vendor/cssminify/spec/tests/webkit-transform.css.min +1 -0
  106. data/vendor/cssminify/spec/tests/zeros.css +12 -0
  107. data/vendor/cssminify/spec/tests/zeros.css.min +1 -0
  108. metadata +223 -0
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ coverage
6
+ rdoc
7
+ doc
8
+ .yardoc
9
+ .rspec
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
7
+ script: bundle exec rspec spec
@@ -0,0 +1,12 @@
1
+ ### 1.0.2 (30 June 2012)
2
+
3
+ * Removed unnecessary Bundler dependency
4
+
5
+ ### 1.0.1 (30 June 2012)
6
+
7
+ * Updated cssmin.rb to 1.0.1
8
+ * Updated tests
9
+
10
+ ## 1.0.0 (29 June 2012)
11
+
12
+ First release
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cssminify.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Matthias Siegel (matthias.siegel@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ Note: the included Ruby port of YUI compressor has a different license. See the [source code](https://github.com/matthiassiegel/cssminify/blob/master/lib/cssminify/cssmin.rb) for details.
@@ -0,0 +1,64 @@
1
+ # CSSminify [![Build Status](https://secure.travis-ci.org/matthiassiegel/cssminify.png)](http://travis-ci.org/matthiassiegel/cssminify)
2
+
3
+ CSS minification with YUI compressor, but as native Ruby port.
4
+
5
+ The CSSminify gem provides CSS compression using YUI compressor. Instead of wrapping around the Java or Javascript version of YUI compressor it uses a native [Ruby port](https://github.com/matthiassiegel/cssmin) of the CSS engine. Therefore this gem has no dependencies.
6
+
7
+ In basic benchmarks the Ruby version performed about as good as the Java jar. It currently passes all CSS test cases included with the YUI compressor Java source code.
8
+
9
+ Main motivation for the Ruby port and this gem was to reduce dependencies like Java.
10
+
11
+ ## Installation
12
+ Install CSSminify from RubyGems:
13
+
14
+ gem install cssminify
15
+
16
+ Or include it in your project's Gemfile:
17
+
18
+ gem 'cssminify'
19
+
20
+ ## Usage
21
+
22
+ require 'cssminify'
23
+
24
+ CSSminify.compress('/* a comment */ .test { display: block; }')
25
+ # => minified CSS
26
+
27
+ CSSminify.compress(File.read('path/to/styles.css'))
28
+ # => minified CSS
29
+
30
+ CSSminify.compress(File.open('path/to/styles.css'))
31
+ # => minified CSS
32
+
33
+ # Alternatively use instance method...
34
+ compressor = CSSminify.new
35
+ compressor.compress(File.read("path/to/styles.css"))
36
+ # => minified CSS
37
+
38
+ Files or strings are acceptable as input.
39
+
40
+ You can pass in a second argument to control the maximum output line length (default 5000 characters):
41
+
42
+ CSSminify.compress(File.read("path/to/styles.css"), 200)
43
+
44
+ Note: in most cases line length will only be approximated.
45
+
46
+ ## Rails asset pipeline
47
+ Rails 3.1 integrated [Sprockets](https://github.com/sstephenson/sprockets) to provide asset packaging and minimising out of the box. For CSS compression it relies on the [yui-compressor gem](https://github.com/sstephenson/ruby-yui-compressor) which requires Java. To use CSSminify instead, edit your config/application.rb file:
48
+
49
+ config.assets.css_compressor = CSSminify.new
50
+
51
+ ## Compatibility
52
+ Tested with Ruby 1.9.2, 1.9.3, jruby-19mode, rbx-19mode
53
+
54
+ ## Changelog
55
+ See [CHANGES](https://github.com/matthiassiegel/cssminify/blob/master/CHANGES.md).
56
+
57
+ ## Copyright
58
+
59
+ ### CSSminify gem and documentation
60
+ Copyright (c) 2012 Matthias Siegel (matthias.siegel@gmail.com)
61
+ See [LICENSE](https://github.com/matthiassiegel/cssminify/blob/master/LICENSE.md) for details.
62
+
63
+ ### YUI compressor
64
+ See [file](https://github.com/matthiassiegel/cssminify/blob/master/lib/cssminify/cssmin.rb).
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "cssminify/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cssminify"
7
+ s.version = CSSminify::VERSION
8
+ s.author = "Matthias Siegel"
9
+ s.email = "matthias.siegel@gmail.com"
10
+ s.homepage = "https://github.com/matthiassiegel/cssminify"
11
+ s.summary = "CSS minification with YUI compressor, but as native Ruby port."
12
+ s.description = <<-EOF
13
+ The CSSminify gem provides CSS compression using YUI compressor. Instead of wrapping around the Java or Javascript version of YUI compressor it uses a native Ruby port of the CSS engine. Therefore this gem has no dependencies.
14
+ EOF
15
+
16
+ s.extra_rdoc_files = [
17
+ "CHANGES.md",
18
+ "LICENSE.md",
19
+ "README.md"
20
+ ]
21
+
22
+ s.license = "MIT"
23
+ s.rubyforge_project = "cssminify"
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- spec/*`.split("\n")
27
+ s.require_paths = ["lib"]
28
+
29
+ s.add_development_dependency "rspec", "~> 2.7"
30
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ require "cssminify/cssmin"
4
+ require "cssminify/version"
5
+
6
+ class CSSminify
7
+
8
+ def initialize
9
+ end
10
+
11
+
12
+ #
13
+ # Compress CSS with YUI
14
+ #
15
+ # @param [String, #read] CSS String or IO-like object that supports #read
16
+ # @param [Integer] length Maximum line length
17
+ # @return [String] Compressed CSS
18
+ def self.compress(source, length = 5000)
19
+ self.new.compress(source, length)
20
+ end
21
+
22
+
23
+ #
24
+ # Compress CSS with YUI
25
+ #
26
+ # @param [String, #read] CSS String or IO-like object that supports #read
27
+ # @param [Integer] length Maximum line length
28
+ # @return [String] Compressed CSS
29
+ def compress(source = '', length = 5000)
30
+ source = source.respond_to?(:read) ? source.read : source.to_s
31
+
32
+ CssCompressor.compress(source, length)
33
+ end
34
+ end
@@ -0,0 +1,383 @@
1
+ #
2
+ # cssmin.rb - 1.0.1
3
+ # Author: Matthias Siegel - https://github.com/matthiassiegel/cssmin
4
+ # This is a Ruby port of the CSS minification tool
5
+ # distributed with YUICompressor, based on the original Java
6
+ # code and the Javascript port by Stoyan Stefanov.
7
+ # Permission is hereby granted to use the Ruby version under the same
8
+ # conditions as YUICompressor (original YUICompressor note below).
9
+ #
10
+ #
11
+ # YUI Compressor
12
+ # http://developer.yahoo.com/yui/compressor/
13
+ # Author: Julien Lecomte - http://www.julienlecomte.net/
14
+ # Author: Isaac Schlueter - http://foohack.com/
15
+ # Author: Stoyan Stefanov - http://phpied.com/
16
+ # Copyright (c) 2011 Yahoo! Inc. All rights reserved.
17
+ # The copyrights embodied in the content of this file are licensed
18
+ # by Yahoo! Inc. under the BSD (revised) open source license.
19
+ #
20
+
21
+ module CssCompressor
22
+
23
+ def self.compress(css, linebreakpos = 5000)
24
+
25
+ #
26
+ # Support for various input types
27
+ #
28
+ if css.respond_to?(:read)
29
+ css = css.read
30
+ elsif css.respond_to?(:path)
31
+ css = File.read(css.path)
32
+ end
33
+
34
+ @@preservedTokens = []
35
+ comments = []
36
+ startIndex = 0
37
+
38
+ #
39
+ # Extract data urls
40
+ #
41
+ css = extractDataUrls(css)
42
+
43
+ #
44
+ # Collect all comment blocks...
45
+ #
46
+ while (startIndex = css.index(/\/\*/, startIndex)) != nil
47
+ endIndex = css.index(/\*\//, startIndex + 2)
48
+ endIndex = css.length if endIndex.nil?
49
+
50
+ comments << css[(startIndex + 2)...endIndex]
51
+
52
+ css = css[0...(startIndex + 2)] + '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_' + (comments.length - 1).to_s + '___' + css[endIndex..-1]
53
+ startIndex += 2
54
+ end
55
+
56
+ #
57
+ # Preserve strings so their content doesn't get accidentally minified
58
+ #
59
+ css = css.gsub(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/) { |match|
60
+ quote = match[0, 1]
61
+ match = match[1...-1]
62
+
63
+ #
64
+ # Maybe the string contains a comment-like substring?
65
+ # One, maybe more? put'em back then
66
+ #
67
+ unless match.index('___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_').nil?
68
+ comments.each_index { |i| match = match.gsub(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/, comments[i]) }
69
+ end
70
+
71
+ #
72
+ # Minify alpha opacity in filter strings
73
+ #
74
+ match = match.gsub(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, 'alpha(opacity=')
75
+
76
+ @@preservedTokens << match
77
+
78
+ quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___" + quote
79
+ }
80
+
81
+ #
82
+ # Strings are safe, now wrestle the comments
83
+ #
84
+ for i in 0...comments.length
85
+ token = comments[i]
86
+ placeholder = /___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/
87
+
88
+ #
89
+ # ! in the first position of the comment means preserve
90
+ # so push to the preserved tokens keeping the !
91
+ #
92
+ if token[0] === '!'
93
+ @@preservedTokens << token
94
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
95
+ next
96
+ end
97
+
98
+ #
99
+ # \ in the last position looks like hack for Mac/IE5
100
+ # shorten that to /*\*/ and the next one to /**/
101
+ #
102
+ if token[(token.length - 1)..-1] === '\\'
103
+ @@preservedTokens << '\\'
104
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
105
+
106
+ i += 1 # Attn: advancing the loop
107
+
108
+ @@preservedTokens << ''
109
+ css = css.gsub(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
110
+ next
111
+ end
112
+
113
+ #
114
+ # Keep empty comments after child selectors (IE7 hack)
115
+ # E.g. html >/**/ body
116
+ #
117
+ if token.length == 0
118
+ startIndex = css.index(placeholder)
119
+
120
+ if startIndex and startIndex > 2
121
+ if css[startIndex - 3] === '>'
122
+ @@preservedTokens << ''
123
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
124
+ end
125
+ end
126
+ end
127
+
128
+ #
129
+ # In all other cases kill the comment
130
+ #
131
+ css = css.gsub(/\/\*___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___\*\//, '')
132
+ end
133
+
134
+ #
135
+ # Shorten all whitespace strings to single spaces
136
+ #
137
+ css = css.gsub(/\s+/, ' ')
138
+
139
+ #
140
+ # Remove the spaces before the things that should not have spaces before them.
141
+ # But, be careful not to turn "p :link {...}" into "p:link{...}"
142
+ # Swap out any pseudo-class colons with the token, and then swap back.
143
+ #
144
+ css = css.gsub(/(^|\})(([^\{:])+:)+([^\{]*\{)/) { |m| m.gsub(/:/, '___YUICSSMIN_PSEUDOCLASSCOLON___') }
145
+ css = css.gsub(/\s+([!{};:>+\(\)\],])/) { $1.to_s }
146
+ css = css.gsub(/___YUICSSMIN_PSEUDOCLASSCOLON___/, ':')
147
+
148
+ #
149
+ # Retain space for special IE6 cases
150
+ #
151
+ css = css.gsub(/:first-(line|letter)(\{|,)/i) { ":first-#{$1.to_s.downcase} #{$2.to_s}" }
152
+
153
+ #
154
+ # No space after the end of a preserved comment
155
+ #
156
+ css = css.gsub(/\*\/\s+/, '*/')
157
+
158
+ #
159
+ # If there is a @charset, then only allow one, and push to the top of the file.
160
+ #
161
+ css = css.gsub(/^(.*)(@charset "[^"]*";)/i) { $2.to_s + $1.to_s }
162
+ css = css.gsub(/^(\s*@charset [^;]+;\s*)+/i) { $1.to_s }
163
+
164
+ #
165
+ # Put the space back in some cases, to support stuff like
166
+ # @media screen and (-webkit-min-device-pixel-ratio:0){
167
+ #
168
+ css = css.gsub(/\band\(/i, 'and (')
169
+
170
+ #
171
+ # Remove the spaces after the things that should not have spaces after them.
172
+ #
173
+ css = css.gsub(/([!{}:;>+\(\[,])\s+/) { $1.to_s }
174
+
175
+ #
176
+ # Remove unnecessary semicolons
177
+ #
178
+ css = css.gsub(/;+\}/, '}')
179
+
180
+ #
181
+ # Replace 0(px,em,%) with 0
182
+ #
183
+ css = css.gsub(/(^|[^0-9])(?:0?\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)/i) { $1.to_s + '0' }
184
+
185
+ #
186
+ # Replace 0 0 0 0; with 0
187
+ #
188
+ css = css.gsub(/:0 0 0 0(;|\})/) { ':0' + $1.to_s }
189
+ css = css.gsub(/:0 0 0(;|\})/) { ':0' + $1.to_s }
190
+ css = css.gsub(/:0 0(;|\})/) { ':0' + $1.to_s }
191
+
192
+ #
193
+ # Replace background-position:0; with background-position:0 0;
194
+ # Same for transform-origin
195
+ #
196
+ css = css.gsub(/(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|\})/i) { "#{$1.to_s.downcase}:0 0#{$2.to_s}" }
197
+
198
+ #
199
+ # Replace 0.6 to .6, but only when preceded by : or a white-space
200
+ #
201
+ css = css.gsub(/(:|\s)0+\.(\d+)/) { "#{$1.to_s}.#{$2.to_s}" }
202
+
203
+ #
204
+ # Shorten colors from rgb(51,102,153) to #336699
205
+ # This makes it more likely that it'll get further compressed in the next step.
206
+ #
207
+ css = css.gsub(/rgb\s*\(\s*([0-9,\s]+)\s*\)(\d+%)?/i) {
208
+ rgbcolors = $1.to_s.split(',')
209
+ i = 0
210
+
211
+ while i < rgbcolors.length
212
+ rgbcolors[i] = rgbcolors[i].to_i.to_s(16)
213
+
214
+ if rgbcolors[i].length === 1
215
+ rgbcolors[i] = '0' + rgbcolors[i]
216
+ end
217
+
218
+ i += 1
219
+ end
220
+
221
+ unless $2.to_s.empty?
222
+ rgbcolors << (' ' + $2.to_s)
223
+ end
224
+
225
+ '#' + rgbcolors.join('')
226
+ }
227
+
228
+ #
229
+ # Shorten colors from #AABBCC to #ABC. Note that we want to make sure
230
+ # the color is not preceded by either ", " or =. Indeed, the property
231
+ # filter: chroma(color="#FFFFFF");
232
+ # would become
233
+ # filter: chroma(color="#FFF");
234
+ # which makes the filter break in IE.
235
+ # We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} )
236
+ # We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD)
237
+ #
238
+ rest = css
239
+ new_css = ''
240
+
241
+ while m = rest.match(/(\=\s*?["']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(:?\}|[^0-9a-f{][^{]*?\})/i) do
242
+ #
243
+ # Normal color value
244
+ #
245
+ if m[1].nil?
246
+ #
247
+ # Color value that can be shortened
248
+ #
249
+ if m[2].to_s.downcase == m[3].to_s.downcase && m[4].to_s.downcase == m[5].to_s.downcase && m[6].to_s.downcase == m[7].to_s.downcase
250
+ color = '#' + m[2].to_s.downcase + m[4].to_s.downcase + m[6].to_s.downcase
251
+ shift = 7
252
+
253
+ #
254
+ # Color value that can't be shortened
255
+ #
256
+ else
257
+ color = '#' + m[2].to_s.downcase + m[3].to_s.downcase + m[4].to_s.downcase + m[5].to_s.downcase + m[6].to_s.downcase + m[7].to_s.downcase
258
+ shift = 7
259
+ end
260
+
261
+ #
262
+ # Filter property that needs to stay the way it is
263
+ #
264
+ else
265
+ color = m[1].to_s + '#' + m[2].to_s + m[3].to_s + m[4].to_s + m[5].to_s + m[6].to_s + m[7].to_s
266
+ shift = color.length
267
+ end
268
+
269
+ new_css += m.pre_match + color
270
+ rest.slice!(rest.index(m.pre_match || 0), m.pre_match.length + shift)
271
+
272
+ end
273
+ css = new_css + rest
274
+
275
+ #
276
+ # border: none -> border:0
277
+ #
278
+ css = css.gsub(/(border|border-top|border-right|border-bottom|border-left|outline|background):none(;|\})/i) { "#{$1.to_s.downcase}:0#{$2.to_s}" }
279
+
280
+ #
281
+ # Shorter opacity IE filter
282
+ #
283
+ css = css.gsub(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, 'alpha(opacity=')
284
+
285
+ #
286
+ # Remove empty rules.
287
+ #
288
+ css = css.gsub(/[^\};\{\/]+\{\}/, '')
289
+
290
+ #
291
+ # Some source control tools don't like it when files containing lines longer
292
+ # than, say 8000 characters, are checked in. The linebreak option is used in
293
+ # that case to split long lines after a specific column.
294
+ #
295
+ if linebreakpos
296
+ startIndex = 0
297
+ i = 0
298
+ while i < css.length
299
+ i = i + 1
300
+ if css[i - 1] === '}' && i - startIndex > linebreakpos
301
+ css = css.slice(0, i) + "\n" + css.slice(i, css.length - i)
302
+ startIndex = i
303
+ end
304
+ end
305
+ end
306
+
307
+ #
308
+ # Replace multiple semi-colons in a row by a single one
309
+ #
310
+ css = css.gsub(/;;+/, ';')
311
+
312
+ #
313
+ # Restore preserved comments and strings
314
+ #
315
+ for i in 0...@@preservedTokens.length do
316
+ css = css.gsub(/___YUICSSMIN_PRESERVED_TOKEN_#{i}___/) { @@preservedTokens[i] }
317
+ end
318
+
319
+ #
320
+ # Remove leading and trailing whitespace
321
+ #
322
+ css = css.chomp.strip
323
+ end
324
+
325
+
326
+
327
+
328
+ private
329
+
330
+
331
+ #
332
+ # Utility method to replace all data urls with tokens before we start
333
+ # compressing, to avoid performance issues running some of the subsequent
334
+ # regexes against large strings chunks.
335
+ #
336
+ # @param [String] css The input css
337
+ # @returns [String] The processed css
338
+ #
339
+ def self.extractDataUrls(css)
340
+ new_css = ''
341
+
342
+ while m = css.match(/url\(\s*(["']?)data\:/i) do
343
+ startIndex = m.begin(0) + 4 # "url(".length()
344
+ terminator = m[1] # ', " or empty (not quoted)
345
+ terminator = ')' if terminator.empty?
346
+ foundTerminator = false
347
+ endIndex = m.end(0) - 1
348
+
349
+ while !foundTerminator && endIndex + 1 <= css.length
350
+ endIndex = css.index(terminator, endIndex + 1)
351
+
352
+ #
353
+ # endIndex == 0 doesn't really apply here
354
+ #
355
+ if endIndex > 0 && css[endIndex - 1] != '\\'
356
+ foundTerminator = true
357
+ endIndex = css.index(')', endIndex) if terminator != ')'
358
+ end
359
+ end
360
+
361
+ new_css += css[0...m.begin(0)]
362
+
363
+ if foundTerminator
364
+ token = css[startIndex...endIndex]
365
+ token = token.gsub(/\s+/, '')
366
+ @@preservedTokens << token
367
+
368
+ new_css += "url(___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___)"
369
+
370
+ #
371
+ # No end terminator found, re-add the whole match
372
+ #
373
+ else
374
+ new_css += css[m.begin(0)...m.end(0)]
375
+ end
376
+
377
+ css = css[(endIndex + 1)..-1]
378
+ end
379
+
380
+ css = new_css + css
381
+ end
382
+
383
+ end