merb-assets 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +4 -0
- data/Rakefile +44 -0
- data/TODO +5 -0
- data/lib/merb-assets.rb +14 -0
- data/lib/merb-assets/assets.rb +198 -0
- data/lib/merb-assets/assets_mixin.rb +562 -0
- metadata +70 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 YOUR NAME
|
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.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
PLUGIN = "merb-assets"
|
5
|
+
NAME = "merb-assets"
|
6
|
+
VERSION = "0.9.2"
|
7
|
+
AUTHOR = "Ezra Zygmuntowicz"
|
8
|
+
EMAIL = "ez@engineyard.com"
|
9
|
+
HOMEPAGE = "http://merb-plugins.rubyforge.org/merb-assets/"
|
10
|
+
SUMMARY = "Merb plugin that provides the helpers for assets and asset bundling"
|
11
|
+
|
12
|
+
spec = Gem::Specification.new do |s|
|
13
|
+
s.name = NAME
|
14
|
+
s.version = VERSION
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
18
|
+
s.summary = SUMMARY
|
19
|
+
s.description = s.summary
|
20
|
+
s.author = AUTHOR
|
21
|
+
s.email = EMAIL
|
22
|
+
s.homepage = HOMEPAGE
|
23
|
+
s.add_dependency('merb-core', '>= 0.9.2')
|
24
|
+
s.require_path = 'lib'
|
25
|
+
s.autorequire = PLUGIN
|
26
|
+
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
30
|
+
pkg.gem_spec = spec
|
31
|
+
end
|
32
|
+
|
33
|
+
task :install => [:package] do
|
34
|
+
sh %{sudo gem install pkg/#{NAME}-#{VERSION} --no-update-sources --no-update-sources}
|
35
|
+
end
|
36
|
+
|
37
|
+
namespace :jruby do
|
38
|
+
|
39
|
+
desc "Run :package and install the resulting .gem with jruby"
|
40
|
+
task :install => :package do
|
41
|
+
sh %{#{SUDO} jruby -S gem install pkg/#{NAME}-#{Merb::VERSION}.gem --no-rdoc --no-ri}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/TODO
ADDED
data/lib/merb-assets.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'merb-assets/assets'
|
2
|
+
require 'merb-assets/assets_mixin'
|
3
|
+
|
4
|
+
Merb::BootLoader.before_app_loads do
|
5
|
+
Merb::Controller.send(:include, Merb::AssetsMixin)
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
Merb::Plugins.config[:asset_helpers] = {
|
10
|
+
:max_hosts => 4,
|
11
|
+
:asset_domain => "assets%s",
|
12
|
+
:domain => "my-awesome-domain.com",
|
13
|
+
:use_ssl => false
|
14
|
+
} if Merb::Plugins.config[:asset_helpers].nil?
|
@@ -0,0 +1,198 @@
|
|
1
|
+
module Merb
|
2
|
+
module Assets
|
3
|
+
|
4
|
+
# Check whether the assets should be bundled.
|
5
|
+
#
|
6
|
+
# ==== Returns
|
7
|
+
# Boolean::
|
8
|
+
# True if the assets should be bundled (e.g., production mode or
|
9
|
+
# :bundle_assets is explicitly enabled).
|
10
|
+
def self.bundle?
|
11
|
+
(Merb.environment == 'production') ||
|
12
|
+
(!!Merb::Config[:bundle_assets])
|
13
|
+
end
|
14
|
+
|
15
|
+
# Helpers for handling asset files.
|
16
|
+
module AssetHelpers
|
17
|
+
# :nodoc:
|
18
|
+
ASSET_FILE_EXTENSIONS = {
|
19
|
+
:javascript => ".js",
|
20
|
+
:stylesheet => ".css"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Returns the URI path to a particular asset file. If +local_path+ is
|
24
|
+
# true, returns the path relative to the Merb.root, not the public
|
25
|
+
# directory. Uses the path_prefix, if any is configured.
|
26
|
+
#
|
27
|
+
# ==== Parameters
|
28
|
+
# asset_type<Symbol>:: Type of the asset (e.g. :javascript).
|
29
|
+
# filename<~to_s>:: The path to the file.
|
30
|
+
# local_path<Boolean>::
|
31
|
+
# If true, the returned path will be relative to the Merb.root,
|
32
|
+
# otherwise it will be the public URI path. Defaults to false.
|
33
|
+
#
|
34
|
+
# ==== Returns
|
35
|
+
# String:: The path to the asset.
|
36
|
+
#
|
37
|
+
# ==== Examples
|
38
|
+
# asset_path(:javascript, :dingo)
|
39
|
+
# # => "/javascripts/dingo.js"
|
40
|
+
#
|
41
|
+
# asset_path(:javascript, :dingo, true)
|
42
|
+
# # => "public/javascripts/dingo.js"
|
43
|
+
def asset_path(asset_type, filename, local_path = false)
|
44
|
+
filename = filename.to_s
|
45
|
+
if filename !~ /#{'\\' + ASSET_FILE_EXTENSIONS[asset_type]}\Z/
|
46
|
+
filename << ASSET_FILE_EXTENSIONS[asset_type]
|
47
|
+
end
|
48
|
+
filename = "/#{asset_type}s/#{filename}"
|
49
|
+
if local_path
|
50
|
+
return "public#{filename}"
|
51
|
+
else
|
52
|
+
return "#{Merb::Config[:path_prefix]}#{filename}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Helper for creating unique paths to a file name
|
58
|
+
# Can increase speend for browsers that are limited to a certain number of connections per host
|
59
|
+
# for downloading static files (css, js, images...)
|
60
|
+
class UniqueAssetPath
|
61
|
+
class << self
|
62
|
+
@@config = Merb::Plugins.config[:asset_helpers]
|
63
|
+
|
64
|
+
# Builds the path to the file based on the name
|
65
|
+
#
|
66
|
+
# ==== Parameters
|
67
|
+
# filename<String>:: Name of file to generate path for
|
68
|
+
#
|
69
|
+
# ==== Returns
|
70
|
+
# String:: The path to the asset.
|
71
|
+
#
|
72
|
+
# ==== Examples
|
73
|
+
# build("/javascripts/my_fancy_script.js")
|
74
|
+
# # => "https://assets5.my-awesome-domain.com/javascripts/my_fancy_script.js"
|
75
|
+
#
|
76
|
+
def build(filename)
|
77
|
+
#%{#{(USE_SSL ? 'https' : 'http')}://#{sprintf(@@config[:asset_domain],self.calculate_host_id(file))}.#{@@config[:domain]}/#{filename}}
|
78
|
+
path = @@config[:use_ssl] ? 'https://' : 'http://'
|
79
|
+
path << sprintf(@@config[:asset_domain],self.calculate_host_id(filename)) << ".#{@@config[:domain]}"
|
80
|
+
path << "/" if filename.index('/') != 0
|
81
|
+
path << filename
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
# Calculates the id for the host
|
87
|
+
def calculate_host_id(filename)
|
88
|
+
ascii_total = 0
|
89
|
+
filename.each_byte {|byte|
|
90
|
+
ascii_total += byte
|
91
|
+
}
|
92
|
+
(ascii_total % @@config[:max_hosts] + 1)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# An abstract class for bundling text assets into single files.
|
98
|
+
class AbstractAssetBundler
|
99
|
+
class << self
|
100
|
+
|
101
|
+
# ==== Parameters
|
102
|
+
# &block:: A block to add as a post-bundle callback.
|
103
|
+
#
|
104
|
+
# ==== Examples
|
105
|
+
# add_callback { |filename| `yuicompressor #{filename}` }
|
106
|
+
def add_callback(&block)
|
107
|
+
callbacks << block
|
108
|
+
end
|
109
|
+
alias_method :after_bundling, :add_callback
|
110
|
+
|
111
|
+
# Retrieve existing callbacks.
|
112
|
+
#
|
113
|
+
# ==== Returns
|
114
|
+
# Array[Proc]:: An array of existing callbacks.
|
115
|
+
def callbacks
|
116
|
+
@callbacks ||= []
|
117
|
+
return @callbacks
|
118
|
+
end
|
119
|
+
|
120
|
+
# The type of asset for which the bundler is responsible. Override
|
121
|
+
# this method in your bundler code.
|
122
|
+
#
|
123
|
+
# ==== Raises
|
124
|
+
# NotImplementedError:: This method is implemented by the bundler.
|
125
|
+
#
|
126
|
+
# ==== Returns
|
127
|
+
# Symbol:: The type of the asset
|
128
|
+
def asset_type
|
129
|
+
raise NotImplementedError, "should return a symbol for the first argument to be passed to asset_path"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# ==== Parameters
|
134
|
+
# name<~to_s>::
|
135
|
+
# Name of the bundle. If name is true, it will be converted to :all.
|
136
|
+
# *files<String>:: Names of the files to bundle.
|
137
|
+
def initialize(name, *files)
|
138
|
+
@bundle_name = name == true ? :all : name
|
139
|
+
@bundle_filename = asset_path(self.class.asset_type, @bundle_name, true)
|
140
|
+
@files = files.map { |f| asset_path(self.class.asset_type, f, true) }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Creates the new bundled file, executing all the callbacks.
|
144
|
+
#
|
145
|
+
# ==== Returns
|
146
|
+
# Symbol:: Name of the bundle.
|
147
|
+
def bundle!
|
148
|
+
# TODO: Move this file check out into an in-memory cache. Also, push it out to the helper level so we don't have to create the helper object.
|
149
|
+
unless File.exist?(@bundle_filename)
|
150
|
+
bundle_files(@bundle_filename, *@files)
|
151
|
+
self.class.callbacks.each { |c| c.call(@bundle_filename) }
|
152
|
+
end
|
153
|
+
return @bundle_name
|
154
|
+
end
|
155
|
+
|
156
|
+
protected
|
157
|
+
|
158
|
+
include Merb::Assets::AssetHelpers # for asset_path
|
159
|
+
|
160
|
+
# Bundle all the files into one.
|
161
|
+
#
|
162
|
+
# ==== Parameters
|
163
|
+
# filename<String>:: Name of the bundle file.
|
164
|
+
# *files<String>:: Filenames to be bundled.
|
165
|
+
def bundle_files(filename, *files)
|
166
|
+
File.open(filename, "w") do |f|
|
167
|
+
files.each { |file| f.puts(File.read(file)) }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
# Bundles javascripts into a single file:
|
174
|
+
#
|
175
|
+
# javascripts/#{name}.js
|
176
|
+
class JavascriptAssetBundler < AbstractAssetBundler
|
177
|
+
|
178
|
+
# ==== Returns
|
179
|
+
# Symbol:: The asset type, i.e. :javascript.
|
180
|
+
def self.asset_type
|
181
|
+
:javascript
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Bundles stylesheets into a single file:
|
186
|
+
#
|
187
|
+
# stylesheets/#{name}.css
|
188
|
+
class StylesheetAssetBundler < AbstractAssetBundler
|
189
|
+
|
190
|
+
# ==== Returns
|
191
|
+
# Symbol:: The asset type, i.e. :stylesheet.
|
192
|
+
def self.asset_type
|
193
|
+
:stylesheet
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,562 @@
|
|
1
|
+
module Merb
|
2
|
+
# The AssetsMixin module provides a number of helper methods to views for
|
3
|
+
# linking to assets and other pages, dealing with JavaScript and CSS.
|
4
|
+
module AssetsMixin
|
5
|
+
include Merb::Assets::AssetHelpers
|
6
|
+
# :section: Accessing Assets
|
7
|
+
# Merb provides views with convenience methods for links images and other
|
8
|
+
# assets.
|
9
|
+
|
10
|
+
# ==== Parameters
|
11
|
+
# name<~to_s>:: The text of the link.
|
12
|
+
# url<~to_s>:: The URL to link to. Defaults to an empty string.
|
13
|
+
# opts<Hash>:: Additional HTML options for the link.
|
14
|
+
#
|
15
|
+
# ==== Examples
|
16
|
+
# link_to("The Merb home page", "http://www.merbivore.com/")
|
17
|
+
# # => <a href="http://www.merbivore.com/">The Merb home page</a>
|
18
|
+
#
|
19
|
+
# link_to("The Ruby home page", "http://www.ruby-lang.org", {'class' => 'special', 'target' => 'blank'})
|
20
|
+
# # => <a href="http://www.ruby-lang.org" class="special" target="blank">The Ruby home page</a>
|
21
|
+
#
|
22
|
+
# link_to p.title, "/blog/show/#{p.id}"
|
23
|
+
# # => <a href="blog/show/13">The Entry Title</a>
|
24
|
+
#
|
25
|
+
def link_to(name, url='', opts={})
|
26
|
+
opts[:href] ||= url
|
27
|
+
%{<a #{ opts.to_xml_attributes }>#{name}</a>}
|
28
|
+
end
|
29
|
+
|
30
|
+
# ==== Parameters
|
31
|
+
# img<~to_s>:: The image path.
|
32
|
+
# opts<Hash>:: Additional options for the image tag (see below).
|
33
|
+
#
|
34
|
+
# ==== Options (opts)
|
35
|
+
# :path<String>::
|
36
|
+
# Sets the path prefix for the image. Defaults to "/images/" or whatever
|
37
|
+
# is specified in Merb::Config. This is ignored if img is an absolute
|
38
|
+
# path or full URL.
|
39
|
+
#
|
40
|
+
# All other options set HTML attributes on the tag.
|
41
|
+
#
|
42
|
+
# ==== Examples
|
43
|
+
# image_tag('foo.gif')
|
44
|
+
# # => <img src='/images/foo.gif' />
|
45
|
+
#
|
46
|
+
# image_tag('foo.gif', :class => 'bar')
|
47
|
+
# # => <img src='/images/foo.gif' class='bar' />
|
48
|
+
#
|
49
|
+
# image_tag('foo.gif', :path => '/files/')
|
50
|
+
# # => <img src='/files/foo.gif' />
|
51
|
+
#
|
52
|
+
# image_tag('http://test.com/foo.gif')
|
53
|
+
# # => <img src="http://test.com/foo.gif">
|
54
|
+
#
|
55
|
+
# image_tag('charts', :path => '/dynamic/')
|
56
|
+
# or
|
57
|
+
# image_tag('/dynamic/charts')
|
58
|
+
# # => <img src="/dynamic/charts">
|
59
|
+
def image_tag(img, opts={})
|
60
|
+
if img[0].chr == '/'
|
61
|
+
opts[:src] = img
|
62
|
+
else
|
63
|
+
opts[:path] ||=
|
64
|
+
if img =~ %r{^https?://}
|
65
|
+
''
|
66
|
+
else
|
67
|
+
if Merb::Config[:path_prefix]
|
68
|
+
Merb::Config[:path_prefix] + '/images/'
|
69
|
+
else
|
70
|
+
'/images/'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
opts[:src] ||= opts.delete(:path) + img
|
74
|
+
end
|
75
|
+
%{<img #{ opts.to_xml_attributes } />}
|
76
|
+
end
|
77
|
+
|
78
|
+
# :section: JavaScript related functions
|
79
|
+
#
|
80
|
+
|
81
|
+
# ==== Parameters
|
82
|
+
# javascript<String>:: Text to escape for use in JavaScript.
|
83
|
+
#
|
84
|
+
# ==== Examples
|
85
|
+
# escape_js("'Lorem ipsum!' -- Some guy")
|
86
|
+
# # => "\\'Lorem ipsum!\\' -- Some guy"
|
87
|
+
#
|
88
|
+
# escape_js("Please keep text\nlines as skinny\nas possible.")
|
89
|
+
# # => "Please keep text\\nlines as skinny\\nas possible."
|
90
|
+
def escape_js(javascript)
|
91
|
+
(javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
|
92
|
+
end
|
93
|
+
|
94
|
+
# ==== Parameters
|
95
|
+
# name<~to_s>:: The text in the link.
|
96
|
+
# function<~to_s>:: The onClick event in JavaScript.
|
97
|
+
#
|
98
|
+
# ==== Examples
|
99
|
+
# link_to_function('Click me', "alert('hi!')")
|
100
|
+
# # => <a href="#" onclick="alert('hi!'); return false;">Click me</a>
|
101
|
+
#
|
102
|
+
# link_to_function('Add to cart', "item_total += 1; alert('Item added!');")
|
103
|
+
# # => <a href="#" onclick="item_total += 1; alert('Item added!'); return false;">Add to cart</a>
|
104
|
+
def link_to_function(name, function)
|
105
|
+
%{<a href="#" onclick="#{function}; return false;">#{name}</a>}
|
106
|
+
end
|
107
|
+
|
108
|
+
# ==== Parameters
|
109
|
+
# data<Object>::
|
110
|
+
# Object to translate into JSON. If the object does not respond to
|
111
|
+
# :to_json, then data.inspect.to_json is returned instead.
|
112
|
+
#
|
113
|
+
# ==== Examples
|
114
|
+
# js({'user' => 'Lewis', 'page' => 'home'})
|
115
|
+
# # => "{\"user\":\"Lewis\",\"page\":\"home\"}"
|
116
|
+
#
|
117
|
+
# js([ 1, 2, {"a"=>3.141}, false, true, nil, 4..10 ])
|
118
|
+
# # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
|
119
|
+
def js(data)
|
120
|
+
if data.respond_to? :to_json
|
121
|
+
data.to_json
|
122
|
+
else
|
123
|
+
data.inspect.to_json
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# :section: External JavaScript and Stylesheets
|
128
|
+
#
|
129
|
+
# You can use require_js(:prototype) or require_css(:shinystyles)
|
130
|
+
# from any view or layout, and the scripts will only be included once
|
131
|
+
# in the head of the final page. To get this effect, the head of your
|
132
|
+
# layout you will need to include a call to include_required_js and
|
133
|
+
# include_required_css.
|
134
|
+
#
|
135
|
+
# ==== Examples
|
136
|
+
# # File: app/views/layouts/application.html.erb
|
137
|
+
#
|
138
|
+
# <html>
|
139
|
+
# <head>
|
140
|
+
# <%= include_required_js %>
|
141
|
+
# <%= include_required_css %>
|
142
|
+
# </head>
|
143
|
+
# <body>
|
144
|
+
# <%= catch_content :layout %>
|
145
|
+
# </body>
|
146
|
+
# </html>
|
147
|
+
#
|
148
|
+
# # File: app/views/whatever/_part1.herb
|
149
|
+
#
|
150
|
+
# <% require_js 'this' -%>
|
151
|
+
# <% require_css 'that', 'another_one' -%>
|
152
|
+
#
|
153
|
+
# # File: app/views/whatever/_part2.herb
|
154
|
+
#
|
155
|
+
# <% require_js 'this', 'something_else' -%>
|
156
|
+
# <% require_css 'that' -%>
|
157
|
+
#
|
158
|
+
# # File: app/views/whatever/index.herb
|
159
|
+
#
|
160
|
+
# <%= partial(:part1) %>
|
161
|
+
# <%= partial(:part2) %>
|
162
|
+
#
|
163
|
+
# # Will generate the following in the final page...
|
164
|
+
# <html>
|
165
|
+
# <head>
|
166
|
+
# <script src="/javascripts/this.js" type="text/javascript"></script>
|
167
|
+
# <script src="/javascripts/something_else.js" type="text/javascript"></script>
|
168
|
+
# <link href="/stylesheets/that.css" media="all" rel="Stylesheet" type="text/css"/>
|
169
|
+
# <link href="/stylesheets/another_one.css" media="all" rel="Stylesheet" type="text/css"/>
|
170
|
+
# </head>
|
171
|
+
# .
|
172
|
+
# .
|
173
|
+
# .
|
174
|
+
# </html>
|
175
|
+
#
|
176
|
+
# See each method's documentation for more information.
|
177
|
+
|
178
|
+
# :section: Bundling Asset Files
|
179
|
+
#
|
180
|
+
# The key to making a fast web application is to reduce both the amount of
|
181
|
+
# data transfered and the number of client-server interactions. While having
|
182
|
+
# many small, module Javascript or stylesheet files aids in the development
|
183
|
+
# process, your web application will benefit from bundling those assets in
|
184
|
+
# the production environment.
|
185
|
+
#
|
186
|
+
# An asset bundle is a set of asset files which are combined into a single
|
187
|
+
# file. This reduces the number of requests required to render a page, and
|
188
|
+
# can reduce the amount of data transfer required if you're using gzip
|
189
|
+
# encoding.
|
190
|
+
#
|
191
|
+
# Asset bundling is always enabled in production mode, and can be optionally
|
192
|
+
# enabled in all environments by setting the <tt>:bundle_assets</tt> value
|
193
|
+
# in <tt>config/merb.yml</tt> to +true+.
|
194
|
+
#
|
195
|
+
# ==== Examples
|
196
|
+
#
|
197
|
+
# In the development environment, this:
|
198
|
+
#
|
199
|
+
# js_include_tag :prototype, :lowpro, :bundle => true
|
200
|
+
#
|
201
|
+
# will produce two <script> elements. In the production mode, however, the
|
202
|
+
# two files will be concatenated in the order given into a single file,
|
203
|
+
# <tt>all.js</tt>, in the <tt>public/javascripts</tt> directory.
|
204
|
+
#
|
205
|
+
# To specify a different bundle name:
|
206
|
+
#
|
207
|
+
# css_include_tag :typography, :whitespace, :bundle => :base
|
208
|
+
# css_include_tag :header, :footer, :bundle => "content"
|
209
|
+
# css_include_tag :lightbox, :images, :bundle => "lb.css"
|
210
|
+
#
|
211
|
+
# (<tt>base.css</tt>, <tt>content.css</tt>, and <tt>lb.css</tt> will all be
|
212
|
+
# created in the <tt>public/stylesheets</tt> directory.)
|
213
|
+
#
|
214
|
+
# == Callbacks
|
215
|
+
#
|
216
|
+
# To use a Javascript or CSS compressor, like JSMin or YUI Compressor:
|
217
|
+
#
|
218
|
+
# Merb::Assets::JavascriptAssetBundler.add_callback do |filename|
|
219
|
+
# system("/usr/local/bin/yui-compress #{filename}")
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
# Merb::Assets::StylesheetAssetBundler.add_callback do |filename|
|
223
|
+
# system("/usr/local/bin/css-min #{filename}")
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# These blocks will be run after a bundle is created.
|
227
|
+
#
|
228
|
+
# == Bundling Required Assets
|
229
|
+
#
|
230
|
+
# Combining the +require_css+ and +require_js+ helpers with bundling can be
|
231
|
+
# problematic. You may want to separate out the common assets for your
|
232
|
+
# application -- Javascript frameworks, common CSS, etc. -- and bundle those
|
233
|
+
# in a "base" bundle. Then, for each section of your site, bundle the
|
234
|
+
# required assets into a section-specific bundle.
|
235
|
+
#
|
236
|
+
# <b>N.B.: If you bundle an inconsistent set of assets with the same name,
|
237
|
+
# you will have inconsistent results. Be thorough and test often.</b>
|
238
|
+
#
|
239
|
+
# ==== Example
|
240
|
+
#
|
241
|
+
# In your application layout:
|
242
|
+
#
|
243
|
+
# js_include_tag :prototype, :lowpro, :bundle => :base
|
244
|
+
#
|
245
|
+
# In your controller layout:
|
246
|
+
#
|
247
|
+
# require_js :bundle => :posts
|
248
|
+
|
249
|
+
# The require_js method can be used to require any JavaScript file anywhere
|
250
|
+
# in your templates. Regardless of how many times a single script is
|
251
|
+
# included with require_js, Merb will only include it once in the header.
|
252
|
+
#
|
253
|
+
# ==== Parameters
|
254
|
+
# *js<~to_s>:: JavaScript files to include.
|
255
|
+
#
|
256
|
+
# ==== Examples
|
257
|
+
# <% require_js 'jquery' %>
|
258
|
+
# # A subsequent call to include_required_js will render...
|
259
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
260
|
+
#
|
261
|
+
# <% require_js 'jquery', 'effects' %>
|
262
|
+
# # A subsequent call to include_required_js will render...
|
263
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
264
|
+
# # <script src="/javascripts/effects.js" type="text/javascript"></script>
|
265
|
+
#
|
266
|
+
def require_js(*js)
|
267
|
+
@required_js ||= []
|
268
|
+
@required_js |= js
|
269
|
+
end
|
270
|
+
|
271
|
+
# The require_css method can be used to require any CSS file anywhere in
|
272
|
+
# your templates. Regardless of how many times a single stylesheet is
|
273
|
+
# included with require_css, Merb will only include it once in the header.
|
274
|
+
#
|
275
|
+
# ==== Parameters
|
276
|
+
# *css<~to_s>:: CSS files to include.
|
277
|
+
#
|
278
|
+
# ==== Examples
|
279
|
+
# <% require_css('style') %>
|
280
|
+
# # A subsequent call to include_required_css will render...
|
281
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
|
282
|
+
#
|
283
|
+
# <% require_css('style', 'ie-specific') %>
|
284
|
+
# # A subsequent call to include_required_css will render...
|
285
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
|
286
|
+
# # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
|
287
|
+
#
|
288
|
+
def require_css(*css)
|
289
|
+
@required_css ||= []
|
290
|
+
@required_css |= css
|
291
|
+
end
|
292
|
+
|
293
|
+
# A method used in the layout of an application to create +<script>+ tags
|
294
|
+
# to include JavaScripts required in in templates and subtemplates using
|
295
|
+
# require_js.
|
296
|
+
#
|
297
|
+
# ==== Parameters
|
298
|
+
# options<Hash>:: Options to pass to js_include_tag.
|
299
|
+
#
|
300
|
+
# ==== Returns
|
301
|
+
# String:: The JavaScript tag.
|
302
|
+
#
|
303
|
+
# ==== Examples
|
304
|
+
# # my_action.herb has a call to require_js 'jquery'
|
305
|
+
# # File: layout/application.html.erb
|
306
|
+
# include_required_js
|
307
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
308
|
+
#
|
309
|
+
# # my_action.herb has a call to require_js 'jquery', 'effects', 'validation'
|
310
|
+
# # File: layout/application.html.erb
|
311
|
+
# include_required_js
|
312
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
313
|
+
# # <script src="/javascripts/effects.js" type="text/javascript"></script>
|
314
|
+
# # <script src="/javascripts/validation.js" type="text/javascript"></script>
|
315
|
+
#
|
316
|
+
def include_required_js(options = {})
|
317
|
+
return '' if @required_js.nil?
|
318
|
+
js_include_tag(*(@required_js + [options]))
|
319
|
+
end
|
320
|
+
|
321
|
+
# A method used in the layout of an application to create +<link>+ tags for
|
322
|
+
# CSS stylesheets required in in templates and subtemplates using
|
323
|
+
# require_css.
|
324
|
+
#
|
325
|
+
# ==== Parameters
|
326
|
+
# options<Hash>:: Options to pass to css_include_tag.
|
327
|
+
#
|
328
|
+
# ==== Returns
|
329
|
+
# String:: The CSS tag.
|
330
|
+
#
|
331
|
+
# ==== Examples
|
332
|
+
# # my_action.herb has a call to require_css 'style'
|
333
|
+
# # File: layout/application.html.erb
|
334
|
+
# include_required_css
|
335
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
|
336
|
+
#
|
337
|
+
# # my_action.herb has a call to require_js 'style', 'ie-specific'
|
338
|
+
# # File: layout/application.html.erb
|
339
|
+
# include_required_css
|
340
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
|
341
|
+
# # <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
|
342
|
+
#
|
343
|
+
def include_required_css(options = {})
|
344
|
+
return '' if @required_css.nil?
|
345
|
+
css_include_tag(*(@required_css + [options]))
|
346
|
+
end
|
347
|
+
|
348
|
+
# ==== Parameters
|
349
|
+
# *scripts::
|
350
|
+
# The scripts to include. If the last element is a Hash, it will be used
|
351
|
+
# as options (see below). If ".js" is left out from the script names, it
|
352
|
+
# will be added to them.
|
353
|
+
#
|
354
|
+
# ==== Options
|
355
|
+
# :bundle<~to_s>::
|
356
|
+
# The name of the bundle the scripts should be combined into.
|
357
|
+
#
|
358
|
+
# ==== Returns
|
359
|
+
# String:: The JavaScript include tag(s).
|
360
|
+
#
|
361
|
+
# ==== Examples
|
362
|
+
# js_include_tag 'jquery'
|
363
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
364
|
+
#
|
365
|
+
# js_include_tag 'moofx.js', 'upload'
|
366
|
+
# # => <script src="/javascripts/moofx.js" type="text/javascript"></script>
|
367
|
+
# # <script src="/javascripts/upload.js" type="text/javascript"></script>
|
368
|
+
#
|
369
|
+
# js_include_tag :effects
|
370
|
+
# # => <script src="/javascripts/effects.js" type="text/javascript"></script>
|
371
|
+
#
|
372
|
+
# js_include_tag :jquery, :validation
|
373
|
+
# # => <script src="/javascripts/jquery.js" type="text/javascript"></script>
|
374
|
+
# # <script src="/javascripts/validation.js" type="text/javascript"></script>
|
375
|
+
#
|
376
|
+
def js_include_tag(*scripts)
|
377
|
+
options = scripts.last.is_a?(Hash) ? scripts.pop : {}
|
378
|
+
return nil if scripts.empty?
|
379
|
+
|
380
|
+
if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && scripts.size > 1
|
381
|
+
bundler = Merb::Assets::JavascriptAssetBundler.new(bundle_name, *scripts)
|
382
|
+
bundled_asset = bundler.bundle!
|
383
|
+
return js_include_tag(bundled_asset)
|
384
|
+
end
|
385
|
+
|
386
|
+
tags = ""
|
387
|
+
|
388
|
+
for script in scripts
|
389
|
+
attrs = {
|
390
|
+
:src => asset_path(:javascript, script),
|
391
|
+
:type => "text/javascript"
|
392
|
+
}
|
393
|
+
tags << %Q{<script #{attrs.to_xml_attributes}></script>}
|
394
|
+
end
|
395
|
+
|
396
|
+
return tags
|
397
|
+
end
|
398
|
+
|
399
|
+
# ==== Parameters
|
400
|
+
# *stylesheets::
|
401
|
+
# The stylesheets to include. If the last element is a Hash, it will be
|
402
|
+
# used as options (see below). If ".css" is left out from the stylesheet
|
403
|
+
# names, it will be added to them.
|
404
|
+
#
|
405
|
+
# ==== Options
|
406
|
+
# :bundle<~to_s>::
|
407
|
+
# The name of the bundle the stylesheets should be combined into.
|
408
|
+
# :media<~to_s>::
|
409
|
+
# The media attribute for the generated link element. Defaults to :all.
|
410
|
+
#
|
411
|
+
# ==== Returns
|
412
|
+
# String:: The CSS include tag(s).
|
413
|
+
#
|
414
|
+
# ==== Examples
|
415
|
+
# css_include_tag 'style'
|
416
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
417
|
+
#
|
418
|
+
# css_include_tag 'style.css', 'layout'
|
419
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
420
|
+
# # <link href="/stylesheets/layout.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
421
|
+
#
|
422
|
+
# css_include_tag :menu
|
423
|
+
# # => <link href="/stylesheets/menu.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
424
|
+
#
|
425
|
+
# css_include_tag :style, :screen
|
426
|
+
# # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
427
|
+
# # <link href="/stylesheets/screen.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
|
428
|
+
#
|
429
|
+
# css_include_tag :style, :media => :print
|
430
|
+
# # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="utf-8" />
|
431
|
+
#
|
432
|
+
# css_include_tag :style, :charset => 'iso-8859-1'
|
433
|
+
# # => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="iso-8859-1" />
|
434
|
+
def css_include_tag(*stylesheets)
|
435
|
+
options = stylesheets.last.is_a?(Hash) ? stylesheets.pop : {}
|
436
|
+
return nil if stylesheets.empty?
|
437
|
+
|
438
|
+
if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && stylesheets.size > 1
|
439
|
+
bundler = Merb::Assets::StylesheetAssetBundler.new(bundle_name, *stylesheets)
|
440
|
+
bundled_asset = bundler.bundle!
|
441
|
+
return css_include_tag(bundled_asset)
|
442
|
+
end
|
443
|
+
|
444
|
+
tags = ""
|
445
|
+
|
446
|
+
for stylesheet in stylesheets
|
447
|
+
attrs = {
|
448
|
+
:href => asset_path(:stylesheet, stylesheet),
|
449
|
+
:type => "text/css",
|
450
|
+
:rel => "Stylesheet",
|
451
|
+
:charset => options[:charset] || 'utf-8',
|
452
|
+
:media => options[:media] || :all
|
453
|
+
}
|
454
|
+
tags << %Q{<link #{attrs.to_xml_attributes} />}
|
455
|
+
end
|
456
|
+
|
457
|
+
return tags
|
458
|
+
end
|
459
|
+
|
460
|
+
# ==== Parameters
|
461
|
+
# *assets::
|
462
|
+
# The assets to include. These should be the full paths to any static served file
|
463
|
+
#
|
464
|
+
# ==== Returns
|
465
|
+
# Array:: Full unique paths to assets OR
|
466
|
+
# String:: if only a single path is requested
|
467
|
+
# ==== Examples
|
468
|
+
# uniq_path("/javascripts/my.js","/javascripts/my.css")
|
469
|
+
# #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets2.my-awesome-domain.com/javascripts/my.css"]
|
470
|
+
#
|
471
|
+
# uniq_path(["/javascripts/my.js","/stylesheets/my.css"])
|
472
|
+
# #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]
|
473
|
+
#
|
474
|
+
# uniq_path(%w(/javascripts/my.js /stylesheets/my.css))
|
475
|
+
# #=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]
|
476
|
+
#
|
477
|
+
# uniq_path('/stylesheets/somearbitrary.css')
|
478
|
+
# #=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css"
|
479
|
+
#
|
480
|
+
# uniq_path('/images/hostsexypicture.jpg')
|
481
|
+
# #=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg"
|
482
|
+
def uniq_path(*assets)
|
483
|
+
paths = []
|
484
|
+
assets.collect.flatten.each do |filename|
|
485
|
+
paths.push(UniqueAssetPath.build(filename))
|
486
|
+
end
|
487
|
+
paths.length > 1 ? paths : paths.first
|
488
|
+
end
|
489
|
+
|
490
|
+
# ==== Parameters
|
491
|
+
# *assets::
|
492
|
+
# Creates unique paths for javascript files (prepends "/javascripts" and appends ".js")
|
493
|
+
#
|
494
|
+
# ==== Returns
|
495
|
+
# Array:: Full unique paths to assets OR
|
496
|
+
# String:: if only a single path is requested
|
497
|
+
# ==== Examples
|
498
|
+
# uniq_js_path("my")
|
499
|
+
# #=> "http://assets2.my-awesome-domain.com/javascripts/my.js"
|
500
|
+
#
|
501
|
+
# uniq_js_path(["admin/secrets","home/signup"])
|
502
|
+
# #=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js",
|
503
|
+
# "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"]
|
504
|
+
def uniq_js_path(*assets)
|
505
|
+
paths = []
|
506
|
+
assets.collect.flatten.each do |filename|
|
507
|
+
paths.push(UniqueAssetPath.build(asset_path(:javascript,filename,true)))
|
508
|
+
end
|
509
|
+
paths.length > 1 ? paths : paths.first
|
510
|
+
end
|
511
|
+
|
512
|
+
# ==== Parameters
|
513
|
+
# *assets::
|
514
|
+
# Creates unique paths for stylesheet files (prepends "/stylesheets" and appends ".css")
|
515
|
+
#
|
516
|
+
# ==== Returns
|
517
|
+
# Array:: Full unique paths to assets OR
|
518
|
+
# String:: if only a single path is requested
|
519
|
+
# ==== Examples
|
520
|
+
# uniq_css_path("my")
|
521
|
+
# #=> "http://assets2.my-awesome-domain.com/stylesheets/my.css"
|
522
|
+
#
|
523
|
+
# uniq_css_path(["admin/secrets","home/signup"])
|
524
|
+
# #=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css",
|
525
|
+
# "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"]
|
526
|
+
def uniq_css_path(*assets)
|
527
|
+
paths = []
|
528
|
+
assets.collect.flatten.each do |filename|
|
529
|
+
paths.push(UniqueAssetPath.build(asset_path(:stylesheet,filename,true)))
|
530
|
+
end
|
531
|
+
paths.length > 1 ? paths : paths.first
|
532
|
+
end
|
533
|
+
|
534
|
+
# ==== Parameters
|
535
|
+
# *assets::
|
536
|
+
# As js_include_tag but has unique path
|
537
|
+
#
|
538
|
+
# ==== Returns
|
539
|
+
# Array:: Full unique paths to assets OR
|
540
|
+
# String:: if only a single path is requested
|
541
|
+
# ==== Examples
|
542
|
+
# uniq_js_tag("my")
|
543
|
+
# #=> <script type="text/javascript" src="http://assets2.my-awesome-domain.com/javascripts/my.js"></script>
|
544
|
+
def uniq_js_tag(*assets)
|
545
|
+
js_include_tag(uniq_js_path(assets))
|
546
|
+
end
|
547
|
+
|
548
|
+
# ==== Parameters
|
549
|
+
# *assets::
|
550
|
+
# As uniq_css_tag but has unique path
|
551
|
+
#
|
552
|
+
# ==== Returns
|
553
|
+
# Array:: Full unique paths to assets OR
|
554
|
+
# String:: if only a single path is requested
|
555
|
+
# ==== Examples
|
556
|
+
# uniq_css_tag("my")
|
557
|
+
# #=> <link href="http://assets2.my-awesome-domain.com/stylesheets/my.css" type="text/css" />
|
558
|
+
def uniq_css_tag(*assets)
|
559
|
+
css_include_tag(uniq_css_path(assets))
|
560
|
+
end
|
561
|
+
end
|
562
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: merb-assets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ezra Zygmuntowicz
|
8
|
+
autorequire: merb-assets
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-03-24 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: merb-core
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.2
|
23
|
+
version:
|
24
|
+
description: Merb plugin that provides the helpers for assets and asset bundling
|
25
|
+
email: ez@engineyard.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
32
|
+
- LICENSE
|
33
|
+
- TODO
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- TODO
|
39
|
+
- lib/merb-assets
|
40
|
+
- lib/merb-assets/assets.rb
|
41
|
+
- lib/merb-assets/assets_mixin.rb
|
42
|
+
- lib/merb-assets.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://merb-plugins.rubyforge.org/merb-assets/
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.0.1
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: Merb plugin that provides the helpers for assets and asset bundling
|
69
|
+
test_files: []
|
70
|
+
|