middleman-more 3.0.0.beta.1 → 3.0.0.beta.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.
- data/Rakefile +1 -0
- data/features/asset_hash.feature +84 -0
- data/features/cache_buster.feature +5 -4
- data/features/coffee-script.feature +2 -2
- data/features/compass-sprites.feature +6 -0
- data/features/gzip.feature +21 -0
- data/features/{ignore_already_minified.features → ignore_already_minified.feature} +0 -0
- data/features/minify_css.feature +50 -2
- data/features/minify_javascript.feature +89 -6
- data/features/relative_assets.feature +47 -6
- data/features/sass_partials.feature +5 -1
- data/features/sprockets_gems.feature +7 -2
- data/fixtures/asset-hash-app/config.rb +8 -0
- data/fixtures/asset-hash-app/source/images/100px.gif +0 -0
- data/fixtures/asset-hash-app/source/images/100px.jpg +0 -0
- data/fixtures/asset-hash-app/source/images/100px.png +0 -0
- data/fixtures/asset-hash-app/source/index.html.erb +308 -0
- data/fixtures/asset-hash-app/source/javascripts/application.js +8 -0
- data/fixtures/asset-hash-app/source/layout.erb +18 -0
- data/fixtures/asset-hash-app/source/other.html.erb +2 -0
- data/fixtures/asset-hash-app/source/partials.html.erb +1 -0
- data/fixtures/asset-hash-app/source/stylesheets/_partial.sass +2 -0
- data/fixtures/asset-hash-app/source/stylesheets/site.css.scss +4 -0
- data/fixtures/asset-hash-app/source/stylesheets/uses_partials.css.sass +4 -0
- data/fixtures/asset-hash-app/source/subdir/index.html.erb +308 -0
- data/fixtures/asset-hash-host-app/config.rb +6 -0
- data/fixtures/asset-hash-host-app/source/images/100px.gif +0 -0
- data/fixtures/asset-hash-host-app/source/images/100px.jpg +0 -0
- data/fixtures/asset-hash-host-app/source/images/100px.png +0 -0
- data/fixtures/asset-hash-host-app/source/index.html.erb +6 -0
- data/fixtures/asset-hash-host-app/source/layout.erb +17 -0
- data/fixtures/asset-hash-host-app/source/other.html.erb +2 -0
- data/fixtures/asset-hash-host-app/source/stylesheets/site.css.scss +4 -0
- data/fixtures/asset-hash-host-app/source/subdir/index.html.erb +6 -0
- data/fixtures/cache-buster-app/source/cache-buster.html.erb +2 -1
- data/fixtures/compass-sprites-app/config.rb +0 -0
- data/fixtures/compass-sprites-app/source/images/icon/arrow_down.png +0 -0
- data/fixtures/compass-sprites-app/source/images/icon/arrow_left.png +0 -0
- data/fixtures/compass-sprites-app/source/images/icon/arrow_right.png +0 -0
- data/fixtures/compass-sprites-app/source/images/icon/arrow_up.png +0 -0
- data/fixtures/compass-sprites-app/source/stylesheets/site.css.scss +3 -0
- data/fixtures/gzip-app/config.rb +1 -0
- data/fixtures/gzip-app/source/index.html +0 -0
- data/fixtures/gzip-app/source/javascripts/test.js +1 -0
- data/fixtures/gzip-app/source/stylesheets/test.css +1 -0
- data/fixtures/minify-css-app/source/inline-css.html.haml +5 -0
- data/fixtures/minify-css-app/source/more-css/site.css +3 -0
- data/fixtures/minify-css-app/source/stylesheets/site.css.sass +5 -1
- data/fixtures/minify-js-app/config.rb +1 -1
- data/fixtures/minify-js-app/source/inline-js.html.haml +22 -1
- data/fixtures/minify-js-app/source/more-js/other.js +8 -0
- data/fixtures/passthrough-app/config.rb +4 -4
- data/fixtures/passthrough-app/source/inline-css.html.haml +5 -4
- data/fixtures/passthrough-app/source/inline-js.html.haml +22 -1
- data/fixtures/relative-assets-app/config.rb +1 -0
- data/fixtures/relative-assets-app/source/relative_image.html.erb +8 -1
- data/fixtures/sprockets-app/source/library/js/vendored_include.js +1 -0
- data/fixtures/sprockets-app/vendor/assets/javascripts/vendored_js.js +1 -0
- data/lib/middleman-more.rb +23 -9
- data/lib/middleman-more/core_extensions/compass.rb +22 -38
- data/lib/middleman-more/core_extensions/sprockets.rb +41 -123
- data/lib/middleman-more/extensions/asset_hash.rb +132 -0
- data/lib/middleman-more/extensions/cache_buster.rb +5 -6
- data/lib/middleman-more/extensions/gzip.rb +57 -0
- data/lib/middleman-more/extensions/minify_css.rb +73 -7
- data/lib/middleman-more/extensions/minify_css/rainpress.rb +168 -0
- data/lib/middleman-more/extensions/minify_javascript.rb +45 -21
- data/lib/middleman-more/extensions/relative_assets.rb +2 -1
- data/lib/middleman-more/renderers/haml.rb +4 -0
- data/lib/middleman-more/renderers/liquid.rb +6 -1
- data/lib/middleman-more/renderers/markdown.rb +10 -1
- data/lib/middleman-more/renderers/sass.rb +12 -6
- data/lib/middleman-more/renderers/slim.rb +5 -0
- data/middleman-more.gemspec +9 -9
- metadata +192 -178
- data/lib/middleman-more/extensions/minify_css/cssmin.rb +0 -55
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
require 'digest/sha1'
|
|
2
|
+
module Middleman::Extensions
|
|
3
|
+
module AssetHash
|
|
4
|
+
class << self
|
|
5
|
+
def registered(app, options)
|
|
6
|
+
exts = options[:exts] || %w(.ico .manifest .jpg .jpeg .png .gif .js .css)
|
|
7
|
+
|
|
8
|
+
app.ready do
|
|
9
|
+
sitemap.register_resource_list_manipulator(
|
|
10
|
+
:asset_hash,
|
|
11
|
+
AssetHashManager.new(self, exts)
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
use Middleware, :exts => exts, :middleman_app => self
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
alias :included :registered
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class AssetHashManager
|
|
21
|
+
def initialize(app, exts)
|
|
22
|
+
@app = app
|
|
23
|
+
@exts = exts
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Update the main sitemap resource list
|
|
27
|
+
# @return [void]
|
|
28
|
+
def manipulate_resource_list(resources)
|
|
29
|
+
resources.each do |resource|
|
|
30
|
+
if @exts.include? resource.ext
|
|
31
|
+
# figure out the path Sprockets would use for this asset
|
|
32
|
+
if resource.ext == '.js'
|
|
33
|
+
sprockets_path = resource.path.sub(@app.js_dir,'').sub(/^\//,'')
|
|
34
|
+
elsif resource.ext == '.css'
|
|
35
|
+
sprockets_path = resource.path.sub(@app.css_dir,'').sub(/^\//,'')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# See if Sprockets knows about the file
|
|
39
|
+
asset = @app.sprockets.find_asset(sprockets_path) if sprockets_path
|
|
40
|
+
|
|
41
|
+
if asset # if it's a Sprockets asset, ask sprockets for its digest
|
|
42
|
+
digest = asset.digest[0..7]
|
|
43
|
+
elsif resource.template? # if it's a template, render it out
|
|
44
|
+
digest = Digest::SHA1.hexdigest(resource.render)[0..7]
|
|
45
|
+
else # if it's a static file, just hash it
|
|
46
|
+
digest = Digest::SHA1.file(resource.source_file).hexdigest[0..7]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The asset hash middleware is responsible for rewriting references to
|
|
56
|
+
# assets to include their new, hashed name.
|
|
57
|
+
class Middleware
|
|
58
|
+
def initialize(app, options={})
|
|
59
|
+
@rack_app = app
|
|
60
|
+
@exts = options[:exts]
|
|
61
|
+
@exts_regex_text = @exts.map {|e| Regexp.escape(e) }.join('|')
|
|
62
|
+
@middleman_app = options[:middleman_app]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def call(env)
|
|
66
|
+
status, headers, response = @rack_app.call(env)
|
|
67
|
+
|
|
68
|
+
path = @middleman_app.full_path(env["PATH_INFO"])
|
|
69
|
+
dirpath = Pathname.new(File.dirname(path))
|
|
70
|
+
|
|
71
|
+
if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/
|
|
72
|
+
body = extract_response_text(response)
|
|
73
|
+
|
|
74
|
+
if body
|
|
75
|
+
# TODO: This regex will change some paths in plan HTML (not in a tag) - is that OK?
|
|
76
|
+
body.gsub! /([=\'\"\(]\s*)([^\s\'\"\)]+(#{@exts_regex_text}))/ do |match|
|
|
77
|
+
asset_path = $2
|
|
78
|
+
relative_path = Pathname.new(asset_path).relative?
|
|
79
|
+
|
|
80
|
+
asset_path = dirpath.join(asset_path).to_s if relative_path
|
|
81
|
+
|
|
82
|
+
if asset_page = @middleman_app.sitemap.find_resource_by_path(asset_path)
|
|
83
|
+
replacement_path = "/#{asset_page.destination_path}"
|
|
84
|
+
replacement_path = Pathname.new(replacement_path).relative_path_from(dirpath).to_s if relative_path
|
|
85
|
+
|
|
86
|
+
"#{$1}#{replacement_path}"
|
|
87
|
+
else
|
|
88
|
+
match
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
status, headers, response = Rack::Response.new(body, status, headers).finish
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
[status, headers, response]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def extract_response_text(response)
|
|
101
|
+
case(response)
|
|
102
|
+
when String
|
|
103
|
+
response
|
|
104
|
+
when Array
|
|
105
|
+
response.join
|
|
106
|
+
when Rack::Response
|
|
107
|
+
response.body.join
|
|
108
|
+
when Rack::File
|
|
109
|
+
File.read(response.path)
|
|
110
|
+
else
|
|
111
|
+
response.to_s
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
register :asset_hash, AssetHash
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# =================Temp Generate Test data==============================
|
|
122
|
+
# ["jpg", "png", "gif"].each do |ext|
|
|
123
|
+
# [["<p>", "</p>"], ["<p><img src=", " /></p>"], ["<p>background-image:url(", ");</p>"]].each do |outer|
|
|
124
|
+
# [["",""], ["'", "'"], ['"','"']].each do |inner|
|
|
125
|
+
# [["", ""], ["/", ""], ["../", ""], ["../../", ""], ["../../../", ""], ["http://example.com/", ""], ["a","a"], ["1","1"], [".", "."], ["-","-"], ["_","_"]].each do |path_parts|
|
|
126
|
+
# name = 'images/100px.'
|
|
127
|
+
# puts outer[0] + inner[0] + path_parts[0] + name + ext + path_parts[1] + inner[1] + outer[1]
|
|
128
|
+
# end
|
|
129
|
+
# end
|
|
130
|
+
# end
|
|
131
|
+
# puts "<br /><br /><br />"
|
|
132
|
+
# end
|
|
@@ -51,10 +51,9 @@ module Middleman::Extensions
|
|
|
51
51
|
real_path_dynamic = File.join(build_dir, prefix, path)
|
|
52
52
|
real_path_dynamic = File.expand_path(real_path_dynamic, root)
|
|
53
53
|
http_path << "?" + File.mtime(real_path_dynamic).strftime("%s") if File.readable?(real_path_dynamic)
|
|
54
|
-
elsif sitemap.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
http_path << "?" + File.mtime(result[0]).strftime("%s")
|
|
54
|
+
elsif resource = sitemap.find_resource_by_path(real_path_static)
|
|
55
|
+
if !resource.template?
|
|
56
|
+
http_path << "?" + File.mtime(resource.source_file).strftime("%s")
|
|
58
57
|
else
|
|
59
58
|
# It's a template, possible with partials. We can't really know when
|
|
60
59
|
# it's updated, so generate fresh cache buster every time durin
|
|
@@ -70,5 +69,5 @@ module Middleman::Extensions
|
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
# Register the extension
|
|
73
|
-
register :cache_buster, CacheBuster
|
|
74
|
-
end
|
|
72
|
+
# register :cache_buster, CacheBuster
|
|
73
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'zlib'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'find'
|
|
4
|
+
|
|
5
|
+
module Middleman::Extensions
|
|
6
|
+
|
|
7
|
+
# This extension Gzips assets and pages when building.
|
|
8
|
+
# Gzipped assets and pages can be served directly by Apache or
|
|
9
|
+
# Nginx with the proper configuration, and pre-zipping means that we
|
|
10
|
+
# can use a more agressive compression level at no CPU cost per request.
|
|
11
|
+
#
|
|
12
|
+
# Use Nginx's gzip_static directive, or AddEncoding and mod_rewrite in Apache
|
|
13
|
+
# to serve your Gzipped files whenever the normal (non-.gz) filename is requested.
|
|
14
|
+
#
|
|
15
|
+
# Pass the :exts options to customize which file extensions get zipped (defaults
|
|
16
|
+
# to .html, .htm, .js and .css.
|
|
17
|
+
#
|
|
18
|
+
module Gzip
|
|
19
|
+
class << self
|
|
20
|
+
def registered(app, options={})
|
|
21
|
+
exts = options[:exts] || %w(.js .css .html .htm)
|
|
22
|
+
|
|
23
|
+
app.send :include, InstanceMethods
|
|
24
|
+
|
|
25
|
+
app.after_build do |builder|
|
|
26
|
+
Find.find(self.class.inst.build_dir) do |path|
|
|
27
|
+
next if File.directory? path
|
|
28
|
+
if exts.include? File.extname(path)
|
|
29
|
+
new_size = gzip_file(path, builder)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias :included :registered
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module InstanceMethods
|
|
39
|
+
def gzip_file(path, builder)
|
|
40
|
+
input_file = File.open(path, 'r').read
|
|
41
|
+
output_filename = path + '.gz'
|
|
42
|
+
File.open(output_filename, 'w') do |f|
|
|
43
|
+
gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
|
|
44
|
+
gz.write input_file
|
|
45
|
+
gz.close
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
old_size = File.size(path)
|
|
49
|
+
new_size = File.size(output_filename)
|
|
50
|
+
|
|
51
|
+
size_change_word = (old_size - new_size) > 0 ? 'smaller' : 'larger'
|
|
52
|
+
|
|
53
|
+
builder.say_status :gzip, "#{output_filename} (#{number_to_human_size((old_size - new_size).abs)} #{size_change_word})"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -9,18 +9,84 @@ module Middleman::Extensions
|
|
|
9
9
|
|
|
10
10
|
# Once registered
|
|
11
11
|
def registered(app)
|
|
12
|
-
|
|
12
|
+
app.set :css_compressor, false
|
|
13
|
+
|
|
13
14
|
app.after_configuration do
|
|
14
|
-
|
|
15
|
-
require "middleman-more/extensions/minify_css/
|
|
16
|
-
set :css_compressor, ::
|
|
15
|
+
unless respond_to?(:css_compressor) && css_compressor
|
|
16
|
+
require "middleman-more/extensions/minify_css/rainpress"
|
|
17
|
+
set :css_compressor, ::Rainpress
|
|
17
18
|
end
|
|
19
|
+
|
|
20
|
+
# Setup Rack to watch for inline JS
|
|
21
|
+
use InlineCSSRack, :compressor => css_compressor
|
|
18
22
|
end
|
|
19
23
|
end
|
|
20
24
|
alias :included :registered
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
|
-
|
|
27
|
+
|
|
28
|
+
# Rack middleware to look for JS in HTML and compress it
|
|
29
|
+
class InlineCSSRack
|
|
30
|
+
|
|
31
|
+
# Init
|
|
32
|
+
# @param [Class] app
|
|
33
|
+
# @param [Hash] options
|
|
34
|
+
def initialize(app, options={})
|
|
35
|
+
@app = app
|
|
36
|
+
@compressor = options[:compressor]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Rack interface
|
|
40
|
+
# @param [Rack::Environmemt] env
|
|
41
|
+
# @return [Array]
|
|
42
|
+
def call(env)
|
|
43
|
+
status, headers, response = @app.call(env)
|
|
44
|
+
|
|
45
|
+
path = env["PATH_INFO"]
|
|
46
|
+
|
|
47
|
+
if path.end_with?('.html') || path.end_with?('.php')
|
|
48
|
+
uncompressed_source = extract_response_text(response)
|
|
49
|
+
|
|
50
|
+
minified = uncompressed_source.gsub(/(<style[^>]*>\s*(?:\/\*<!\[CDATA\[\*\/\n)?)(.*?)((?:(?:\n\s*)?\/\*\]\]>\*\/)?\s*<\/style>)/m) do |match|
|
|
51
|
+
first = $1
|
|
52
|
+
css = $2
|
|
53
|
+
last = $3
|
|
54
|
+
|
|
55
|
+
minified_css = @compressor.compress(css)
|
|
56
|
+
|
|
57
|
+
first << minified_css << last
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
headers["Content-Length"] = ::Rack::Utils.bytesize(minified).to_s
|
|
61
|
+
response = [minified]
|
|
62
|
+
elsif path.end_with?('.css') && path !~ /\.min\./
|
|
63
|
+
uncompressed_source = extract_response_text(response)
|
|
64
|
+
minified_css = @compressor.compress(uncompressed_source)
|
|
65
|
+
|
|
66
|
+
headers["Content-Length"] = ::Rack::Utils.bytesize(minified_css).to_s
|
|
67
|
+
response = [minified_css]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
[status, headers, response]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def extract_response_text(response)
|
|
76
|
+
case(response)
|
|
77
|
+
when String
|
|
78
|
+
response
|
|
79
|
+
when Array
|
|
80
|
+
response.join
|
|
81
|
+
when Rack::Response
|
|
82
|
+
response.body.join
|
|
83
|
+
when Rack::File
|
|
84
|
+
File.read(response.path)
|
|
85
|
+
else
|
|
86
|
+
response.to_s
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
24
90
|
# Register extension
|
|
25
|
-
register :minify_css, MinifyCss
|
|
26
|
-
end
|
|
91
|
+
# register :minify_css, MinifyCss
|
|
92
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# == Information
|
|
2
|
+
#
|
|
3
|
+
# This is the main class of Rainpress, create an instance of it to compress
|
|
4
|
+
# your CSS-styles.
|
|
5
|
+
#
|
|
6
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
|
7
|
+
#
|
|
8
|
+
# <b>Options:</b>
|
|
9
|
+
#
|
|
10
|
+
# * <tt>:comments</tt> - if set to false, comments will not be removed
|
|
11
|
+
# * <tt>:newlines</tt> - if set to false, newlines will not be removed
|
|
12
|
+
# * <tt>:spaces</tt> - if set to false, spaces will not be removed
|
|
13
|
+
# * <tt>:colors</tt> - if set to false, colors will not be modified
|
|
14
|
+
# * <tt>:misc</tt> - if set to false, miscellaneous compression parts will be skipped
|
|
15
|
+
class Rainpress
|
|
16
|
+
# Quick-compress the styles.
|
|
17
|
+
# This eliminates the need to create an instance of the class
|
|
18
|
+
def self.compress(style, options = {})
|
|
19
|
+
self.new(style, options).compress!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(style, opts = {})
|
|
23
|
+
@style = style
|
|
24
|
+
@opts = {
|
|
25
|
+
:comments => true,
|
|
26
|
+
:newlines => true,
|
|
27
|
+
:spaces => true,
|
|
28
|
+
:colors => true,
|
|
29
|
+
:misc => true
|
|
30
|
+
}
|
|
31
|
+
@opts.merge! opts
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Run the compressions and return the newly compressed text
|
|
35
|
+
def compress!
|
|
36
|
+
remove_comments! if @opts[:comments]
|
|
37
|
+
remove_newlines! if @opts[:newlines]
|
|
38
|
+
remove_spaces! if @opts[:spaces]
|
|
39
|
+
shorten_colors! if @opts[:colors]
|
|
40
|
+
do_misc! if @opts[:misc]
|
|
41
|
+
@style
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Remove all comments out of the CSS-Document
|
|
45
|
+
#
|
|
46
|
+
# Only /* text */ comments are supported.
|
|
47
|
+
# Attention: If you are doing css hacks for IE using the comment tricks,
|
|
48
|
+
# they will be removed using this function. Please consider for IE css style
|
|
49
|
+
# corrections the usage of conditionals comments in your (X)HTML document.
|
|
50
|
+
def remove_comments!
|
|
51
|
+
input = @style
|
|
52
|
+
@style = ''
|
|
53
|
+
|
|
54
|
+
while input.length > 0 do
|
|
55
|
+
pos = input.index("/*");
|
|
56
|
+
|
|
57
|
+
# No more comments
|
|
58
|
+
if pos == nil
|
|
59
|
+
@style += input
|
|
60
|
+
input = '';
|
|
61
|
+
else # Comment beginning at pos
|
|
62
|
+
@style += input[0..(pos-1)] if pos > 0 # only append text if there is some
|
|
63
|
+
input = input[(pos+2)..-1]
|
|
64
|
+
# Comment ending at pos
|
|
65
|
+
pos = input.index("*/")
|
|
66
|
+
input = input[(pos+2)..-1]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Remove all newline characters
|
|
72
|
+
#
|
|
73
|
+
# We take care of Windows(\r\n), Unix(\n) and Mac(\r) newlines.
|
|
74
|
+
def remove_newlines!
|
|
75
|
+
@style.gsub! /\n|\r/, ''
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Remove unneeded spaces
|
|
79
|
+
#
|
|
80
|
+
# 1. Turn mutiple spaces into a single
|
|
81
|
+
# 2. Remove spaces around ;:{},
|
|
82
|
+
# 3. Remove tabs
|
|
83
|
+
def remove_spaces!
|
|
84
|
+
@style.gsub! /\s*(\s|;|:|\}|\{|,)\s*/, '\1'
|
|
85
|
+
@style.gsub! "\t", ''
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Replace color values with their shorter equivalent
|
|
89
|
+
#
|
|
90
|
+
# 1. Turn rgb(,,)-colors into #-values
|
|
91
|
+
# 2. Shorten #AABBCC down to #ABC
|
|
92
|
+
# 3. Replace names with their shorter hex-equivalent
|
|
93
|
+
# * white -> #fff
|
|
94
|
+
# * black -> #000
|
|
95
|
+
# 4. Replace #-values with their shorter name
|
|
96
|
+
# * #f00 -> red
|
|
97
|
+
def shorten_colors!
|
|
98
|
+
# rgb(50,101,152) to #326598
|
|
99
|
+
@style.gsub! /rgb\s*\(\s*([0-9,\s]+)\s*\)/ do |match|
|
|
100
|
+
out = '#'
|
|
101
|
+
$1.split(',').each do |num|
|
|
102
|
+
out += '0' if num.to_i < 16
|
|
103
|
+
out += num.to_i.to_s(16) # convert to hex
|
|
104
|
+
end
|
|
105
|
+
out
|
|
106
|
+
end
|
|
107
|
+
# Convert #AABBCC to #ABC, keep if preceed by a '='
|
|
108
|
+
@style.gsub! /([^\"'=\s])(\s*)#([\da-f])\3([\da-f])\4([\da-f])\5/i, '\1#\3\4\5'
|
|
109
|
+
|
|
110
|
+
# At the moment we assume that colours only appear before ';' or '}' and
|
|
111
|
+
# after a ':', if there could be an occurence of a color before or after
|
|
112
|
+
# an other character, submit either a bug report or, better, a patch that
|
|
113
|
+
# enables Rainpress to take care of this.
|
|
114
|
+
|
|
115
|
+
# shorten several names to numbers
|
|
116
|
+
## shorten white -> #fff
|
|
117
|
+
@style.gsub! /:\s*white\s*(;|\})/, ':#fff\1'
|
|
118
|
+
|
|
119
|
+
## shorten black -> #000
|
|
120
|
+
@style.gsub! /:\s*black\s*(;|\})/, ':#000\1'
|
|
121
|
+
|
|
122
|
+
# shotern several numbers to names
|
|
123
|
+
## shorten #f00 or #ff0000 -> red
|
|
124
|
+
@style.gsub! /:\s*#f{1,2}0{2,4}(;|\})/i, ':red\1'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Do miscellaneous compression methods on the style.
|
|
128
|
+
def do_misc!
|
|
129
|
+
# Replace 0(pt,px,em,%) with 0 but only when preceded by : or a white-space
|
|
130
|
+
@style.gsub! /([\s:]+)(0)(px|em|%|in|cm|mm|pc|pt|ex)/i, '\1\2'
|
|
131
|
+
|
|
132
|
+
# Replace :0 0 0 0(;|}) with :0(;|})
|
|
133
|
+
@style.gsub! /:0 0 0 0(;|\})/, ':0\1'
|
|
134
|
+
|
|
135
|
+
# Replace :0 0 0(;|}) with :0(;|})
|
|
136
|
+
@style.gsub! /:0 0 0(;|\})/, ':0\1'
|
|
137
|
+
|
|
138
|
+
# Replace :0 0(;|}) with :0(;|})
|
|
139
|
+
@style.gsub! /:0 0(;|\})/, ':0\1'
|
|
140
|
+
|
|
141
|
+
# Replace background-position:0; with background-position:0 0;
|
|
142
|
+
@style.gsub! 'background-position:0;', 'background-position:0 0;'
|
|
143
|
+
|
|
144
|
+
# Replace 0.6 to .6, but only when preceded by : or a white-space
|
|
145
|
+
@style.gsub! /[:\s]0+\.(\d+)/ do |match|
|
|
146
|
+
match.sub '0', '' # only first '0' !!
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Replace multiple ';' with a single ';'
|
|
150
|
+
@style.gsub! /[;]+/, ';'
|
|
151
|
+
|
|
152
|
+
# Replace ;} with }
|
|
153
|
+
@style.gsub! ';}', '}'
|
|
154
|
+
|
|
155
|
+
# Replace font-weight:normal; with 400
|
|
156
|
+
@style.gsub! /font-weight[\s]*:[\s]*normal[\s]*(;|\})/i,'font-weight:400\1'
|
|
157
|
+
@style.gsub! /font[\s]*:[\s]*normal[\s;\}]*/ do |match|
|
|
158
|
+
match.sub 'normal', '400'
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Replace font-weight:bold; with 700
|
|
162
|
+
@style.gsub! /font-weight[\s]*:[\s]*bold[\s]*(;|\})/,'font-weight:700\1'
|
|
163
|
+
@style.gsub! /font[\s]*:[\s]*bold[\s;\}]*/ do |match|
|
|
164
|
+
match.sub 'bold', '700'
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|