jammit-core 0.1.0
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/LICENSE +22 -0
- data/README +24 -0
- data/README.rdoc +17 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/bin/jammit +13 -0
- data/lib/assets.example.yml +14 -0
- data/lib/jammit-core.rb +219 -0
- data/lib/jammit-core/cli.rb +87 -0
- data/lib/jammit-core/command_line.rb +79 -0
- data/lib/jammit-core/compressor.rb +214 -0
- data/lib/jammit-core/config.rb +82 -0
- data/lib/jammit-core/dependencies.rb +23 -0
- data/lib/jammit-core/helper.rb +77 -0
- data/lib/jammit-core/jst.js +1 -0
- data/lib/jammit-core/packager.rb +163 -0
- data/lib/jammit-core/routes.rb +16 -0
- data/lib/jammit-core/ui.rb +55 -0
- data/test/config/assets-broken.yml +16 -0
- data/test/config/assets-closure.yml +16 -0
- data/test/config/assets-compression-disabled.yml +16 -0
- data/test/config/assets-css.yml +6 -0
- data/test/config/assets-erb.yml +13 -0
- data/test/config/assets-no-java.yml +16 -0
- data/test/config/assets.yml +13 -0
- data/test/fixtures/jammed/test-closure.js +1 -0
- data/test/fixtures/jammed/test-datauri.css +1 -0
- data/test/fixtures/jammed/test-line-break.css +8 -0
- data/test/fixtures/jammed/test-mhtml.css +17 -0
- data/test/fixtures/jammed/test-uncompressed.css +36 -0
- data/test/fixtures/jammed/test-uncompressed.js +13 -0
- data/test/fixtures/jammed/test.css +1 -0
- data/test/fixtures/jammed/test.js +1 -0
- data/test/fixtures/jammed/test.jst +6 -0
- data/test/fixtures/jammed/test2.jst +6 -0
- data/test/fixtures/src/test1.css +11 -0
- data/test/fixtures/src/test1.js +8 -0
- data/test/fixtures/src/test1.jst +1 -0
- data/test/fixtures/src/test2.css +20 -0
- data/test/fixtures/src/test2.js +5 -0
- data/test/fixtures/src/test2.jst +5 -0
- data/test/fixtures/src/test_fonts.css +5 -0
- data/test/fixtures/tags/css_includes.html +6 -0
- data/test/fixtures/tags/css_individual_includes.html +3 -0
- data/test/fixtures/tags/css_plain_includes.html +1 -0
- data/test/fixtures/tags/css_print.html +6 -0
- data/test/public/embed/DroidSansMono.eot +0 -0
- data/test/public/embed/DroidSansMono.ttf +0 -0
- data/test/public/embed/asterisk_orange.png +0 -0
- data/test/public/embed/asterisk_yellow.png +0 -0
- data/test/test_helper.rb +44 -0
- data/test/unit/command_line_test.rb +28 -0
- data/test/unit/test_closure_compressor.rb +24 -0
- data/test/unit/test_compressor.rb +24 -0
- data/test/unit/test_configuration.rb +71 -0
- data/test/unit/test_in_the_wrong_directory.rb +40 -0
- data/test/unit/test_jammit_helpers.rb +44 -0
- data/test/unit/test_packager.rb +77 -0
- metadata +187 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../jammit')
|
3
|
+
|
4
|
+
module Jammit
|
5
|
+
|
6
|
+
# The @CommandLine@ is able to compress, pre-package, and pre-gzip all the
|
7
|
+
# assets specified in the configuration file, in order to avoid an initial
|
8
|
+
# round of slow requests after a fresh deployment.
|
9
|
+
class CommandLine
|
10
|
+
|
11
|
+
BANNER = <<-EOS
|
12
|
+
|
13
|
+
Usage: jammit OPTIONS
|
14
|
+
|
15
|
+
Run jammit inside a Rails application to compresses all JS, CSS,
|
16
|
+
and JST according to config/assets.yml, saving the packaged
|
17
|
+
files and corresponding gzipped versions.
|
18
|
+
|
19
|
+
If you're using "embed_assets", and you wish to precompile the
|
20
|
+
MHTML stylesheet variants, you must specify the "base-url".
|
21
|
+
|
22
|
+
Options:
|
23
|
+
EOS
|
24
|
+
|
25
|
+
# The @Jammit::CommandLine@ runs from the contents of @ARGV@.
|
26
|
+
def initialize
|
27
|
+
parse_options
|
28
|
+
ensure_configuration_file
|
29
|
+
Jammit.load_configuration(@options[:config_path])
|
30
|
+
Jammit.packager.force = @options[:force]
|
31
|
+
Jammit.packager.precache_all(@options[:output_folder], @options[:base_url])
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Make sure that we have a readable configuration file. The @jammit@
|
38
|
+
# command can't run without one.
|
39
|
+
def ensure_configuration_file
|
40
|
+
config = @options[:config_path]
|
41
|
+
return true if File.exists?(config) && File.readable?(config)
|
42
|
+
puts "Could not find the asset configuration file \"#{config}\""
|
43
|
+
exit(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Uses @OptionParser@ to grab the options: *--output*, *--config*, and
|
47
|
+
# *--base-url*...
|
48
|
+
def parse_options
|
49
|
+
@options = {
|
50
|
+
:config_path => Jammit::DEFAULT_CONFIG_PATH,
|
51
|
+
:output_folder => nil,
|
52
|
+
:base_url => nil,
|
53
|
+
:force => false
|
54
|
+
}
|
55
|
+
@option_parser = OptionParser.new do |opts|
|
56
|
+
opts.on('-o', '--output PATH', 'output folder for packages (default: "public/assets")') do |output_folder|
|
57
|
+
@options[:output_folder] = output_folder
|
58
|
+
end
|
59
|
+
opts.on('-c', '--config PATH', 'path to assets.yml (default: "config/assets.yml")') do |config_path|
|
60
|
+
@options[:config_path] = config_path
|
61
|
+
end
|
62
|
+
opts.on('-u', '--base-url URL', 'base URL for MHTML (ex: "http://example.com")') do |base_url|
|
63
|
+
@options[:base_url] = base_url
|
64
|
+
end
|
65
|
+
opts.on('-f', '--force', 'force a rebuild of all assets') do |force|
|
66
|
+
@options[:force] = force
|
67
|
+
end
|
68
|
+
opts.on_tail('-v', '--version', 'display Jammit version') do
|
69
|
+
puts "Jammit version #{Jammit::VERSION}"
|
70
|
+
exit
|
71
|
+
end
|
72
|
+
end
|
73
|
+
@option_parser.banner = BANNER
|
74
|
+
@option_parser.parse!(ARGV)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
module Jammit
|
2
|
+
|
3
|
+
# Uses the YUI Compressor or Closure Compiler to compress JavaScript.
|
4
|
+
# Always uses YUI to compress CSS (Which means that Java must be installed.)
|
5
|
+
# Also knows how to create a concatenated JST file.
|
6
|
+
# If "embed_assets" is turned on, creates "mhtml" and "datauri" versions of
|
7
|
+
# all stylesheets, with all enabled assets inlined into the css.
|
8
|
+
class Compressor
|
9
|
+
|
10
|
+
# Mapping from extension to mime-type of all embeddable assets.
|
11
|
+
EMBED_MIME_TYPES = {
|
12
|
+
'.png' => 'image/png',
|
13
|
+
'.jpg' => 'image/jpeg',
|
14
|
+
'.jpeg' => 'image/jpeg',
|
15
|
+
'.gif' => 'image/gif',
|
16
|
+
'.tif' => 'image/tiff',
|
17
|
+
'.tiff' => 'image/tiff',
|
18
|
+
'.ttf' => 'font/truetype',
|
19
|
+
'.otf' => 'font/opentype'
|
20
|
+
}
|
21
|
+
|
22
|
+
# Font extensions for which we allow embedding:
|
23
|
+
EMBED_EXTS = EMBED_MIME_TYPES.keys
|
24
|
+
EMBED_FONTS = ['.ttf', '.otf']
|
25
|
+
|
26
|
+
# Maximum size for embeddable images (an IE8 limitation).
|
27
|
+
MAX_IMAGE_SIZE = 32 * 1024
|
28
|
+
|
29
|
+
# CSS asset-embedding regexes for URL rewriting.
|
30
|
+
EMBED_DETECTOR = /url\(['"]?([^\s)]+\.[a-z]+)(\?\d+)?['"]?\)/
|
31
|
+
EMBEDDABLE = /[\A\/]embed\//
|
32
|
+
EMBED_REPLACER = /url\(__EMBED__([^\s)]+)(\?\d+)?\)/
|
33
|
+
|
34
|
+
# MHTML file constants.
|
35
|
+
MHTML_START = "/*\r\nContent-Type: multipart/related; boundary=\"JAMMIT_MHTML_SEPARATOR\"\r\n\r\n"
|
36
|
+
MHTML_SEPARATOR = "--JAMMIT_MHTML_SEPARATOR\r\n"
|
37
|
+
MHTML_END = "*/\r\n"
|
38
|
+
|
39
|
+
# JST file constants.
|
40
|
+
JST_START = "(function(){"
|
41
|
+
JST_END = "})();"
|
42
|
+
|
43
|
+
COMPRESSORS = {
|
44
|
+
:yui => YUI::JavaScriptCompressor,
|
45
|
+
:closure => Closure::Compiler
|
46
|
+
}
|
47
|
+
|
48
|
+
DEFAULT_OPTIONS = {
|
49
|
+
:yui => {:munge => true},
|
50
|
+
:closure => {}
|
51
|
+
}
|
52
|
+
|
53
|
+
# Creating a compressor initializes the internal YUI Compressor from
|
54
|
+
# the "yui-compressor" gem, or the internal Closure Compiler from the
|
55
|
+
# "closure-compiler" gem.
|
56
|
+
def initialize
|
57
|
+
@css_compressor = YUI::CssCompressor.new(Jammit.config[:css_compressor_options] || {})
|
58
|
+
flavor = Jammit.config[:javascript_compressor] || Jammit::DEFAULT_COMPRESSOR
|
59
|
+
@options = DEFAULT_OPTIONS[flavor].merge(Jammit.config[:compressor_options] || {})
|
60
|
+
@js_compressor = COMPRESSORS[flavor].new(@options)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Concatenate together a list of JavaScript paths, and pass them through the
|
64
|
+
# YUI Compressor (with munging enabled).
|
65
|
+
def compress_js(paths)
|
66
|
+
js = concatenate(paths)
|
67
|
+
Jammit.config[:compress_assets] ? @js_compressor.compress(js) : js
|
68
|
+
end
|
69
|
+
|
70
|
+
# Concatenate and compress a list of CSS stylesheets. When compressing a
|
71
|
+
# :datauri or :mhtml variant, post-processes the result to embed
|
72
|
+
# referenced assets.
|
73
|
+
def compress_css(paths, variant=nil, asset_url=nil)
|
74
|
+
css = concatenate_and_tag_assets(paths, variant)
|
75
|
+
css = @css_compressor.compress(css) if Jammit.compress_assets
|
76
|
+
case variant
|
77
|
+
when nil then return css
|
78
|
+
when :datauri then return with_data_uris(css)
|
79
|
+
when :mhtml then return with_mhtml(css, asset_url)
|
80
|
+
else raise PackageNotFound, "\"#{variant}\" is not a valid stylesheet variant"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Compiles a single JST file by writing out a javascript that adds
|
85
|
+
# template properties to a top-level template namespace object. Adds a
|
86
|
+
# JST-compilation function to the top of the package, unless you've
|
87
|
+
# specified your own preferred function, or turned it off.
|
88
|
+
# JST templates are named with the basename of their file.
|
89
|
+
def compile_jst(paths)
|
90
|
+
namespace = Jammit.template_namespace
|
91
|
+
compiled = paths.map do |path|
|
92
|
+
template_name = File.basename(path, File.extname(path))
|
93
|
+
contents = File.read(path).gsub(/\n/, '').gsub("'", '\\\\\'')
|
94
|
+
"#{namespace}.#{template_name} = #{Jammit.template_function}('#{contents}');"
|
95
|
+
end
|
96
|
+
compiler = Jammit.config[:include_jst_script] ? File.read(Jammit::DEFAULT_JST_SCRIPT) : '';
|
97
|
+
setup_namespace = "#{namespace} = #{namespace} || {};"
|
98
|
+
[JST_START, setup_namespace, compiler, compiled, JST_END].flatten.join("\n")
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# In order to support embedded assets from relative paths, we need to
|
105
|
+
# expand the paths before contatenating the CSS together and losing the
|
106
|
+
# location of the original stylesheet path. Validate the assets while we're
|
107
|
+
# at it.
|
108
|
+
def concatenate_and_tag_assets(paths, variant=nil)
|
109
|
+
stylesheets = [paths].flatten.map do |css_path|
|
110
|
+
File.read(css_path).gsub(EMBED_DETECTOR) do |url|
|
111
|
+
ipath, cpath = Pathname.new($1), Pathname.new(File.expand_path(css_path))
|
112
|
+
is_url = URI.parse($1).absolute?
|
113
|
+
is_url ? url : "url(#{construct_asset_path(ipath, cpath, variant)})"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
stylesheets.join("\n")
|
117
|
+
end
|
118
|
+
|
119
|
+
# Re-write all enabled asset URLs in a stylesheet with their corresponding
|
120
|
+
# Data-URI Base-64 encoded asset contents.
|
121
|
+
def with_data_uris(css)
|
122
|
+
css.gsub(EMBED_REPLACER) do |url|
|
123
|
+
"url(\"data:#{mime_type($1)};charset=utf-8;base64,#{encoded_contents($1)}\")"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Re-write all enabled asset URLs in a stylesheet with the MHTML equivalent.
|
128
|
+
# The newlines ("\r\n") in the following method are critical. Without them
|
129
|
+
# your MHTML will look identical, but won't work.
|
130
|
+
def with_mhtml(css, asset_url)
|
131
|
+
paths, index = {}, 0
|
132
|
+
css = css.gsub(EMBED_REPLACER) do |url|
|
133
|
+
i = paths[$1] ||= "#{index += 1}-#{File.basename($1)}"
|
134
|
+
"url(mhtml:#{asset_url}!#{i})"
|
135
|
+
end
|
136
|
+
mhtml = paths.sort.map do |path, identifier|
|
137
|
+
mime, contents = mime_type(path), encoded_contents(path)
|
138
|
+
[MHTML_SEPARATOR, "Content-Location: #{identifier}\r\n", "Content-Type: #{mime}\r\n", "Content-Transfer-Encoding: base64\r\n\r\n", contents, "\r\n"]
|
139
|
+
end
|
140
|
+
[MHTML_START, mhtml, MHTML_END, css].flatten.join('')
|
141
|
+
end
|
142
|
+
|
143
|
+
# Return a rewritten asset URL for a new stylesheet -- the asset should
|
144
|
+
# be tagged for embedding if embeddable, and referenced at the correct level
|
145
|
+
# if relative.
|
146
|
+
def construct_asset_path(asset_path, css_path, variant)
|
147
|
+
public_path = absolute_path(asset_path, css_path)
|
148
|
+
return "__EMBED__#{public_path}" if embeddable?(public_path, variant)
|
149
|
+
source = asset_path.absolute? ? asset_path.to_s : relative_path(public_path)
|
150
|
+
rewrite_asset_path(source, public_path)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Get the site-absolute public path for an asset file path that may or may
|
154
|
+
# not be relative, given the path of the stylesheet that contains it.
|
155
|
+
def absolute_path(asset_pathname, css_pathname)
|
156
|
+
(asset_pathname.absolute? ?
|
157
|
+
Pathname.new(File.join(PUBLIC_ROOT, asset_pathname)) :
|
158
|
+
css_pathname.dirname + asset_pathname).cleanpath
|
159
|
+
end
|
160
|
+
|
161
|
+
# CSS assets that are referenced by relative paths, and are *not* being
|
162
|
+
# embedded, must be rewritten relative to the newly-merged stylesheet path.
|
163
|
+
def relative_path(absolute_path)
|
164
|
+
File.join('../', absolute_path.sub(PUBLIC_ROOT, ''))
|
165
|
+
end
|
166
|
+
|
167
|
+
# Similar to the AssetTagHelper's method of the same name, this will
|
168
|
+
# append the RAILS_ASSET_ID cache-buster to URLs, if it's defined.
|
169
|
+
def rewrite_asset_path(path, file_path)
|
170
|
+
asset_id = rails_asset_id(file_path)
|
171
|
+
asset_id.blank? ? path : "#{path}?#{asset_id}"
|
172
|
+
end
|
173
|
+
|
174
|
+
# Similar to the AssetTagHelper's method of the same name, this will
|
175
|
+
# determine the correct asset id for a file.
|
176
|
+
def rails_asset_id(path)
|
177
|
+
asset_id = ENV["RAILS_ASSET_ID"]
|
178
|
+
return asset_id if asset_id
|
179
|
+
File.exists?(path) ? File.mtime(path).to_i.to_s : ''
|
180
|
+
end
|
181
|
+
|
182
|
+
# An asset is valid for embedding if it exists, is less than 32K, and is
|
183
|
+
# stored somewhere inside of a folder named "embed".
|
184
|
+
# IE does not support Data-URIs larger than 32K, and you probably shouldn't
|
185
|
+
# be embedding assets that large in any case.
|
186
|
+
def embeddable?(asset_path, variant)
|
187
|
+
font = EMBED_FONTS.include?(asset_path.extname)
|
188
|
+
return false unless variant
|
189
|
+
return false unless asset_path.to_s.match(EMBEDDABLE) && asset_path.exist?
|
190
|
+
return false unless EMBED_EXTS.include?(asset_path.extname)
|
191
|
+
return false unless font || asset_path.size < MAX_IMAGE_SIZE
|
192
|
+
return false if font && variant == :mhtml
|
193
|
+
true
|
194
|
+
end
|
195
|
+
|
196
|
+
# Return the Base64-encoded contents of an asset on a single line.
|
197
|
+
def encoded_contents(asset_path)
|
198
|
+
data = File.open(asset_path, 'rb'){|f| f.read }
|
199
|
+
Base64.encode64(data).gsub(/\n/, '')
|
200
|
+
end
|
201
|
+
|
202
|
+
# Grab the mime-type of an asset, by filename.
|
203
|
+
def mime_type(asset_path)
|
204
|
+
EMBED_MIME_TYPES[File.extname(asset_path)]
|
205
|
+
end
|
206
|
+
|
207
|
+
# Concatenate together a list of asset files.
|
208
|
+
def concatenate(paths)
|
209
|
+
[paths].flatten.map {|p| File.read(p) }.join("\n")
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Jammit
|
2
|
+
module Config
|
3
|
+
|
4
|
+
CONFIG_TEMPLATE = Jammit::ROOT + '/assets.example.yml'
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def dispatch(command, *params)
|
9
|
+
case command
|
10
|
+
when :create
|
11
|
+
create
|
12
|
+
when :set
|
13
|
+
set(params.shift, params.shift)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# load configuration file
|
19
|
+
# @param {String} path
|
20
|
+
# @param {Boolean} force reloading of config file
|
21
|
+
#
|
22
|
+
def load(force=false)
|
23
|
+
raise Jammit::ConfigurationNotFound, "could not find the \"#{Jammit.config_path}\" configuration file" unless File.exists?(Jammit.config_path) && File.readable?(Jammit.config_path)
|
24
|
+
if !@config || force == true
|
25
|
+
@config = YAML.load(ERB.new(File.read(Jammit.config_path)).result)
|
26
|
+
end
|
27
|
+
@config
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
##
|
33
|
+
# Write config to file
|
34
|
+
#
|
35
|
+
def write(config)
|
36
|
+
File.open(Jammit.config_path, "w") {|f|
|
37
|
+
f << config.to_yaml
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# If a config path is given, use that as the root, otherwise use DEFAULT_CONFIG_PATH
|
43
|
+
#
|
44
|
+
def create
|
45
|
+
if File.exists?(Jammit.config_path)
|
46
|
+
raise Jammit::AlreadyConfigured.new(" Config file #{Jammit.config_path} already exists.")
|
47
|
+
end
|
48
|
+
FileUtils.mkdir_p(File.dirname(Jammit.config_path))
|
49
|
+
FileUtils.cp(CONFIG_TEMPLATE, Jammit.config_path)
|
50
|
+
|
51
|
+
parts = Jammit.config_path.split('/')
|
52
|
+
name = parts.pop
|
53
|
+
dir = parts.pop
|
54
|
+
Jammit.ui.confirm(" create #{dir}/#{name}")
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Set a config property in file
|
59
|
+
# @param {String} name
|
60
|
+
# @param {String} value
|
61
|
+
#
|
62
|
+
def set(name, value)
|
63
|
+
value = (value == "true") ? true : (value == "false") ? false : value
|
64
|
+
|
65
|
+
config = load(true)
|
66
|
+
option = config[name]
|
67
|
+
|
68
|
+
# careful not to clobber raexisting values if updating a hash
|
69
|
+
if value.kind_of?(Hash) && option.kind_of?(Hash)
|
70
|
+
value.keys.each do |k|
|
71
|
+
option[k] = value[k]
|
72
|
+
end
|
73
|
+
config.update(name => option)
|
74
|
+
else
|
75
|
+
config.update(name => value)
|
76
|
+
end
|
77
|
+
write(config)
|
78
|
+
Jammit.ui.confirm(" set #{name}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Standard Library Dependencies:
|
2
|
+
require 'uri'
|
3
|
+
require 'erb'
|
4
|
+
require 'zlib'
|
5
|
+
require 'base64'
|
6
|
+
require 'pathname'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
# Pull in some extlib goodies
|
11
|
+
require 'extlib/class'
|
12
|
+
require 'extlib/hash'
|
13
|
+
require 'extlib/mash'
|
14
|
+
require 'extlib/inflection'
|
15
|
+
|
16
|
+
# Gem Dependencies:
|
17
|
+
require 'rubygems'
|
18
|
+
require 'yui/compressor'
|
19
|
+
require 'closure-compiler'
|
20
|
+
|
21
|
+
# Jammit Core:
|
22
|
+
require 'jammit-core/compressor'
|
23
|
+
require 'jammit-core/packager'
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Jammit
|
2
|
+
|
3
|
+
# The Jammit::Helper module, which is made available to every view, provides
|
4
|
+
# helpers for writing out HTML tags for asset packages. In development you
|
5
|
+
# get the ordered list of source files -- in any other environment, a link
|
6
|
+
# to the cached packages.
|
7
|
+
module Helper
|
8
|
+
|
9
|
+
DATA_URI_START = "<!--[if (!IE)|(gte IE 8)]><!-->"
|
10
|
+
DATA_URI_END = "<!--<![endif]-->"
|
11
|
+
MHTML_START = "<!--[if lte IE 7]>"
|
12
|
+
MHTML_END = "<![endif]-->"
|
13
|
+
|
14
|
+
# If embed_assets is turned on, writes out links to the Data-URI and MHTML
|
15
|
+
# versions of the stylesheet package, otherwise the package is regular
|
16
|
+
# compressed CSS, and in development the stylesheet URLs are passed verbatim.
|
17
|
+
def include_stylesheets(*packages)
|
18
|
+
options = packages.extract_options!
|
19
|
+
return individual_stylesheets(packages, options) unless Jammit.package_assets
|
20
|
+
disabled = (options.delete(:embed_assets) == false) || (options.delete(:embed_images) == false)
|
21
|
+
return packaged_stylesheets(packages, options) if disabled || !Jammit.embed_assets
|
22
|
+
return embedded_image_stylesheets(packages, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Writes out the URL to the bundled and compressed javascript package,
|
26
|
+
# except in development, where it references the individual scripts.
|
27
|
+
def include_javascripts(*packages)
|
28
|
+
tags = packages.map do |pack|
|
29
|
+
Jammit.package_assets ? Jammit.asset_url(pack, :js) : Jammit.packager.individual_urls(pack.to_sym, :js)
|
30
|
+
end
|
31
|
+
javascript_include_tag(tags.flatten)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Writes out the URL to the concatenated and compiled JST file -- we always
|
35
|
+
# have to pre-process it, even in development.
|
36
|
+
def include_templates(*packages)
|
37
|
+
javascript_include_tag(packages.map {|pack| Jammit.asset_url(pack, :jst) })
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# HTML tags, in order, for all of the individual stylesheets.
|
44
|
+
def individual_stylesheets(packages, options)
|
45
|
+
tags_with_options(packages, options) {|p| Jammit.packager.individual_urls(p.to_sym, :css) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# HTML tags for the stylesheet packages.
|
49
|
+
def packaged_stylesheets(packages, options)
|
50
|
+
tags_with_options(packages, options) {|p| Jammit.asset_url(p, :css) }
|
51
|
+
end
|
52
|
+
|
53
|
+
# HTML tags for the 'datauri', and 'mhtml' versions of the packaged
|
54
|
+
# stylesheets, using conditional comments to load the correct variant.
|
55
|
+
def embedded_image_stylesheets(packages, options)
|
56
|
+
datauri_tags = tags_with_options(packages, options) {|p| Jammit.asset_url(p, :css, :datauri) }
|
57
|
+
ie_tags = Jammit.mhtml_enabled ?
|
58
|
+
tags_with_options(packages, options) {|p| Jammit.asset_url(p, :css, :mhtml) } :
|
59
|
+
packaged_stylesheets(packages, options)
|
60
|
+
[DATA_URI_START, datauri_tags, DATA_URI_END, MHTML_START, ie_tags, MHTML_END].join("\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Generate the stylesheet tags for a batch of packages, with options, by
|
64
|
+
# yielding each package to a block.
|
65
|
+
def tags_with_options(packages, options)
|
66
|
+
packages = packages.dup
|
67
|
+
packages.map! {|package| yield package }.flatten!
|
68
|
+
packages.push(options) unless options.empty?
|
69
|
+
stylesheet_link_tag(*packages)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# Include the Jammit asset helpers in all views, a-la ApplicationHelper.
|
77
|
+
::ActionView::Base.send(:include, Jammit::Helper)
|