module Merb::AssetsMixin

The AssetsMixin module provides a number of helper methods to views for linking to assets and other pages, dealing with JavaScript and CSS.

Merb provides views with convenience methods for links images and other assets.

Constants

ABSOLUTE_PATH_REGEXP

Public Class Methods

append_random_query_string?(intention, allow_default = true) click to toggle source

This tests whether a random query string shall be appended to a url.

Basically, you tell it your intention and if it's ok to use default config values, and it will either use your intention or the value set in Merb::Config

@example

Merb::AssetsMixin.append_random_query_string?(options[:reload])
Merb::AssetsMixin.append_random_query_string?(options[:reload], !absolute)

@param [Boolean] intention: true if a random string shall be appended @param [Boolean] allow_default: true if it's ok to use Merb::Config @return [Boolean] true if a random query string shall be appended

# File lib/merb-assets/assets_mixin.rb, line 25
def self.append_random_query_string?(intention, allow_default = true)
  intention.nil? && allow_default ? Merb::Config[:reload_templates] : intention
end
append_timestamp_query_string?(intention, allow_default = true) click to toggle source

This tests whether a timestamp query string shall be appended to a url.

@see self.append_random_query_string?

@example

Merb::AssetsMixin.append_timestamp_query_string?(options[:timestamp])
Merb::AssetsMixin.append_timestamp_query_string?(options[:timestamp], !absolute)

@param [Boolean] intention: true if a timestamp string shall be appended @param [Boolean] allow_default: true if it's ok to use Merb::Plugins.config[:asset_timestamp] @return [Boolean] true if a timestamp query string shall be appended

# File lib/merb-assets/assets_mixin.rb, line 40
def self.append_timestamp_query_string?(intention, allow_default = true)
  intention.nil? && allow_default ? Merb::Plugins.config[:asset_helpers][:asset_timestamp] : intention
end

Public Instance Methods

asset_exists?(asset_type, asset_path) click to toggle source

Parameters

asset_type<Symbol>: A symbol representing the type of the asset. asset_path<String>: The path to the asset

Returns

exists?<Boolean>

Examples

This tests whether a give asset exists in the file system.

# File lib/merb-assets/assets_mixin.rb, line 98
def asset_exists?(asset_type, asset_path)
  File.exists?(Merb.root / asset_path(asset_type, asset_path, true))
end
image_tag(img, opts={}) click to toggle source

Generate IMG tag

@param [String, to_s] img The image path. @param [Hash] opts Additional options for the image tag (see below). @option opts [String] :path

Sets the path prefix for the image. Defaults to "/images/" or whatever
is specified in Merb::Config. This is ignored if img is an absolute
path or full URL.

@option opts [Boolean] :reload

Override the Merb::Config[:reload_templates] value. If true, a random query param will be appended
to the image url

@option opts [Boolean, String] :timestamp

Override the Merb::Plugins.config[:asset_helpers][:asset_timestamp] value. If true, a timestamp query param will be appended
to the image url. The value will be File.mtime(Merb.dir_for(:public) / path).
If String is passed than it will be used as the timestamp.

All other options set HTML attributes on the tag.

@example

image_tag('foo.gif')
# => <img src='/images/foo.gif' />

image_tag('foo.gif', :class => 'bar')
# => <img src='/images/foo.gif' class='bar' />

image_tag('foo.gif', :path => '/files/')
# => <img src='/files/foo.gif' />

image_tag('http://test.com/foo.gif')
# => <img src="http://test.com/foo.gif">

image_tag('charts', :path => '/dynamic/')
or
image_tag('/dynamic/charts')
# => <img src="/dynamic/charts">

@return [String]

# File lib/merb-assets/assets_mixin.rb, line 176
def image_tag(img, opts={})
  return "" if img.blank?
  if img[0].chr == Merb::Const::SLASH
    opts[:src] = "#{Merb::Config[:path_prefix]}#{img}"
  else
    opts[:path] ||=
      if img =~ ABSOLUTE_PATH_REGEXP
        absolute = true
        ''
      else
        "#{Merb::Config[:path_prefix]}/images/"
      end
    opts[:src] ||= opts.delete(:path) + img
  end

  opts[:src] = append_query_string(opts[:src],
                                   opts.delete(:reload),
                                   opts.delete(:timestamp),
                                   !absolute) 
  
  %Q{<img #{ opts.to_xml_attributes } />}
end

Bundling Asset Files

↑ top

Public Instance Methods

css_include_tag(*stylesheets) click to toggle source

Generate CSS include tag(s).

@param [Array<*String, Hash>] stylesheets

The stylesheets to include. If the last element is a Hash, it will be
used as options (see below). If ".css" is left out from the stylesheet
names, it will be added to them.

Options

@option opts <String, to_s> charset

Charset which will be used as value for charset attribute

@option opts <String, to_s> bundle

The name of the bundle the stylesheets should be combined into.

@option opts <String, to_s> media

The media attribute for the generated link element. Defaults to :all.

@option opts <String, to_s> prefix

prefix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:css_prefix]

@option opts <String, to_s> suffix

suffix to add to include tag, overrides any set in Merb::Plugins.config[:asset_helpers][:css_suffix]

@option opts <Boolean> reload

Override the Merb::Config[:reload_templates] value. If true, a random query param will be appended
to the css url

@option opts [Boolean, String] :timestamp

Override the Merb::Plugins.config[:asset_helper][:asset_timestamp] value. If true, a timestamp query param will be appended
to the image url. The value will be File.mtime(Merb.dir_for(:public) / path).
If String is passed than it will be used as the timestamp.

@example

 css_include_tag 'style'
 # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

 css_include_tag 'style.css', 'layout'
 # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
 #    <link href="/stylesheets/layout.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

 css_include_tag :menu
 # => <link href="/stylesheets/menu.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

 css_include_tag :style, :screen
 # => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />
 #    <link href="/stylesheets/screen.css" media="all" rel="Stylesheet" type="text/css" charset="utf-8" />

css_include_tag :style, :media => :print
# => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="utf-8" />

css_include_tag :style, :charset => 'iso-8859-1'
# => <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" charset="iso-8859-1" />

css_include_tag :style, :prefix => "http://static.example.com"
# => <link href="http://static.example.com/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" />

css_include_tag :style, :suffix => ".#{MyApp.version}"
# => <link href="/stylesheets/style.1.0.0.css" media="print" rel="Stylesheet" type="text/css" />

@return [String] The CSS include tag(s)

# File lib/merb-assets/assets_mixin.rb, line 622
def css_include_tag(*stylesheets)
  options = stylesheets.last.is_a?(Hash) ? stylesheets.pop : {}
  return nil if stylesheets.empty?

  css_prefix = options[:prefix] || Merb::Plugins.config[:asset_helpers][:css_prefix]
  css_suffix = options[:suffix] || Merb::Plugins.config[:asset_helpers][:css_suffix]

  if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && stylesheets.size > 1
    bundler = Merb::Assets::StylesheetAssetBundler.new(bundle_name, *stylesheets)
    bundled_asset = bundler.bundle!
    return css_include_tag(bundled_asset)
  end

  tags = ""

  reload = options.delete(:reload)
  timestamp = options.delete(:timestamp)
  for stylesheet in stylesheets
    href = css_prefix.to_s + asset_path(:stylesheet, stylesheet)
    
    if css_suffix
      ext_length = ASSET_FILE_EXTENSIONS[:stylesheet].length + 1
      href.insert(-ext_length,css_suffix)
    end
    
    href = append_query_string(href, reload, timestamp)

    attrs = {
      :href => href,
      :type => "text/css",
      :rel => "Stylesheet",
      :charset => options[:charset] || "utf-8",
      :media => options[:media] || :all
    }
    tags << %Q{<link #{attrs.to_xml_attributes} />}
  end

  return tags
end
include_required_css(options = {}) click to toggle source

A method used in the layout of an application to create +<link>+ tags for CSS stylesheets required in in templates and subtemplates using require_css.

Parameters

options<Hash>

Options to pass to css_include_tag.

Returns

String

The CSS tag.

Options

:bundle<~to_s>

The name of the bundle the stylesheets should be combined into.

:media<~to_s>

The media attribute for the generated link element. Defaults to :all.

Examples

# my_action.herb has a call to require_css 'style'
# File: layout/application.html.erb
include_required_css
# => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>

# my_action.herb has a call to require_css 'style', 'ie-specific'
# File: layout/application.html.erb
include_required_css
# => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
#    <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
# File lib/merb-assets/assets_mixin.rb, line 475
def include_required_css(options = {})
  required_css(options).map { |req_js| css_include_tag(*req_js) }.join
end
include_required_js(options = {}) click to toggle source

A method used in the layout of an application to create +<script>+ tags to include JavaScripts required in in templates and subtemplates using require_js.

Parameters

options<Hash>

Options to pass to js_include_tag.

Options

:bundle<~to_s>

The name of the bundle the scripts should be combined into.

Returns

String

The JavaScript tag.

Examples

# my_action.herb has a call to require_js 'jquery'
# File: layout/application.html.erb
include_required_js
# => <script src="/javascripts/jquery.js" type="text/javascript"></script>

# my_action.herb has a call to require_js 'jquery', 'effects', 'validation'
# File: layout/application.html.erb
include_required_js
# => <script src="/javascripts/jquery.js" type="text/javascript"></script>
#    <script src="/javascripts/effects.js" type="text/javascript"></script>
#    <script src="/javascripts/validation.js" type="text/javascript"></script>
# File lib/merb-assets/assets_mixin.rb, line 443
def include_required_js(options = {})
  required_js(options).map { |req_js| js_include_tag(*req_js) }.join
end
js_include_tag(*scripts) click to toggle source

Generate JavaScript include tag(s).

@param [Array] scripts

The scripts to include. If the last element is a Hash, it will be used
as options (see below). If ".js" is left out from the script names, it
will be added to them.

Options

:charset<~to_s>

Charset which will be used as value for charset attribute

:bundle<~to_s>

The name of the bundle the scripts should be combined into.

:prefix<~to_s>

prefix to add to include tag, overrides any set in Merb::Plugins.config[:js_prefix]

:suffix<~to_s>

suffix to add to include tag, overrides any set in Merb::Plugins.config[:js_suffix]

:reload<Boolean>

Override the Merb::Config value. If true, a random query param will be appended to the js url

@option opts [Boolean, String] :timestamp

Override the Merb::Plugins.config[:asset_helpers][:asset_timestamp] value. If true, a timestamp query param will be appended
to the image url. The value will be File.mtime(Merb.dir_for(:public) / path).
If String is passed than it will be used as the timestamp.

@example

js_include_tag 'jquery'
# => <script src="/javascripts/jquery.js" type="text/javascript" charset="utf-8"></script>

js_include_tag 'jquery', :charset => 'iso-8859-1'
# => <script src="/javascripts/jquery.js" type="text/javascript" charset="iso-8859-1"></script>

js_include_tag 'moofx.js', 'upload'
# => <script src="/javascripts/moofx.js" type="text/javascript" charset="utf-8"></script>
#    <script src="/javascripts/upload.js" type="text/javascript" charset="utf-8"></script>

js_include_tag :effects
# => <script src="/javascripts/effects.js" type="text/javascript" charset="utf-8"></script>

js_include_tag :jquery, :validation
# => <script src="/javascripts/jquery.js" type="text/javascript" charset="utf-8"></script>
#    <script src="/javascripts/validation.js" type="text/javascript" charset="utf-8"></script>

js_include_tag :application, :validation, :prefix => "http://cdn.example.com"
# => <script src="http://cdn.example.com/javascripts/application.js" type="text/javascript" charset="utf-8"></script>
#    <script src="http://cdn.example.com/javascripts/validation.js" type="text/javascript" charset="utf-8"></script>

js_include_tag :application, :validation, :suffix => ".#{MyApp.version}"
# => <script src="/javascripts/application.1.0.3.js" type="text/javascript" charset="utf-8"></script>
#    <script src="/javascripts/validation.1.0.3.js" type="text/javascript" charset="utf-8"></script>

@return [String] The JavaScript include tag(s).

# File lib/merb-assets/assets_mixin.rb, line 530
def js_include_tag(*scripts)
  options = scripts.last.is_a?(Hash) ? scripts.pop : {}
  return nil if scripts.empty?

  js_prefix = options[:prefix] || Merb::Plugins.config[:asset_helpers][:js_prefix]
  js_suffix = options[:suffix] || Merb::Plugins.config[:asset_helpers][:js_suffix]
  
  if (bundle_name = options[:bundle]) && Merb::Assets.bundle? && scripts.size > 1
    bundler = Merb::Assets::JavascriptAssetBundler.new(bundle_name, *scripts)
    bundled_asset = bundler.bundle!
    return js_include_tag(bundled_asset)
  end

  tags = ""

  for script in scripts
    src = js_prefix.to_s + asset_path(:javascript, script)
    
    if js_suffix
      ext_length = ASSET_FILE_EXTENSIONS[:javascript].length + 1
      src.insert(-ext_length,js_suffix)
    end

    src = append_query_string(src,
                              options.delete(:reload),
                              options.delete(:timestamp))

    attrs = {
      :src => src,
      :type => "text/javascript",
      :charset => options[:charset] || "utf-8"
    }
    tags << %Q{<script #{attrs.to_xml_attributes}></script>}
  end

  return tags
end
require_css(*css) click to toggle source

The #require_css method can be used to require any CSS file anywhere in your templates. Regardless of how many times a single stylesheet is included with #require_css, Merb will only include it once in the header.

Parameters

*css<~to_s>

CSS files to include.

Examples

<% require_css('style') %>
# A subsequent call to include_required_css will render...
# => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>

<% require_css('style', 'ie-specific') %>
# A subsequent call to include_required_css will render...
# => <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css"/>
#    <link href="/stylesheets/ie-specific.css" media="all" rel="Stylesheet" type="text/css"/>
# File lib/merb-assets/assets_mixin.rb, line 403
def require_css(*css)
  @required_css ||= []
  @required_css << css
end
require_js(*js) click to toggle source

The #require_js method can be used to require any JavaScript file anywhere in your templates. Regardless of how many times a single script is included with #require_js, Merb will only include it once in the header.

Parameters

*js<~to_s>

JavaScript files to include.

Examples

<% require_js 'jquery' %>
# A subsequent call to include_required_js will render...
# => <script src="/javascripts/jquery.js" type="text/javascript"></script>

<% require_js 'jquery', 'effects' %>
# A subsequent call to include_required_js will render...
# => <script src="/javascripts/jquery.js" type="text/javascript"></script>
#    <script src="/javascripts/effects.js" type="text/javascript"></script>
# File lib/merb-assets/assets_mixin.rb, line 373
def require_js(*js)
  @required_js ||= []
  @required_js << js
end
required_css(options = {}) click to toggle source

All css files to include, without duplicates.

Parameters

options<Hash>

Default options to pass to css_include_tag.

# File lib/merb-assets/assets_mixin.rb, line 412
def required_css(options = {})
  extract_required_files(@required_css, options)
end
required_js(options = {}) click to toggle source

All javascript files to include, without duplicates.

Parameters

options<Hash>

Default options to pass to js_include_tag.

# File lib/merb-assets/assets_mixin.rb, line 382
def required_js(options = {})
  extract_required_files(@required_js, options)
end
uniq_css_path(*assets) click to toggle source

Parameters

*assets

Creates unique paths for stylesheet files (prepends “/stylesheets” and appends “.css”)

Returns

Array

Full unique paths to assets OR

String

if only a single path is requested

Examples

uniq_css_path("my")
#=> "http://assets2.my-awesome-domain.com/stylesheets/my.css"

uniq_css_path(["admin/secrets","home/signup"])
#=> ["http://assets2.my-awesome-domain.com/stylesheets/admin/secrets.css",
       "http://assets1.my-awesome-domain.com/stylesheets/home/signup.css"]
# File lib/merb-assets/assets_mixin.rb, line 728
def uniq_css_path(*assets)
  paths = []
  assets.flatten.each do |filename|
    paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:stylesheet,filename)))
  end
  paths.length > 1 ? paths : paths.first
end
uniq_css_tag(*assets) click to toggle source

Parameters

*assets

As #uniq_css_tag but has unique path

Returns

Array

Full unique paths to assets OR

String

if only a single path is requested

Examples

uniq_css_tag("my")
#=> <link href="http://assets2.my-awesome-domain.com/stylesheets/my.css" type="text/css" />
# File lib/merb-assets/assets_mixin.rb, line 760
def uniq_css_tag(*assets)
  css_include_tag(*uniq_css_path(assets))
end
uniq_js_path(*assets) click to toggle source

Parameters

*assets

Creates unique paths for javascript files (prepends “/javascripts” and appends “.js”)

Returns

Array

Full unique paths to assets OR

String

if only a single path is requested

Examples

uniq_js_path("my")
#=> "http://assets2.my-awesome-domain.com/javascripts/my.js"

uniq_js_path(["admin/secrets","home/signup"])
#=> ["http://assets2.my-awesome-domain.com/javascripts/admin/secrets.js",
       "http://assets1.my-awesome-domain.com/javascripts/home/signup.js"]
# File lib/merb-assets/assets_mixin.rb, line 706
def uniq_js_path(*assets)
  paths = []
  assets.flatten.each do |filename|
    paths.push(Merb::Assets::UniqueAssetPath.build(asset_path(:javascript,filename)))
  end
  paths.length > 1 ? paths : paths.first
end
uniq_js_tag(*assets) click to toggle source

Parameters

*assets

As #js_include_tag but has unique path

Returns

Array

Full unique paths to assets OR

String

if only a single path is requested

Examples

uniq_js_tag("my")
#=> <script type="text/javascript" src="http://assets2.my-awesome-domain.com/javascripts/my.js"></script>
# File lib/merb-assets/assets_mixin.rb, line 746
def uniq_js_tag(*assets)
  js_include_tag(*uniq_js_path(assets))
end
uniq_path(*assets) click to toggle source

Parameters

*assets

The assets to include. These should be the full paths to any static served file

Returns

Array

Full unique paths to assets OR

String

if only a single path is requested

Examples

uniq_path("/javascripts/my.js","/javascripts/my.css")
#=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/javascripts/my.css"]

uniq_path(["/javascripts/my.js","/stylesheets/my.css"])
#=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]

uniq_path(%w(/javascripts/my.js /stylesheets/my.css))
#=> ["http://assets2.my-awesome-domain.com/javascripts/my.js", "http://assets1.my-awesome-domain.com/stylesheets/my.css"]

uniq_path('/stylesheets/somearbitrary.css')
#=> "http://assets3.my-awesome-domain.com/stylesheets/somearbitrary.css"

uniq_path('/images/hostsexypicture.jpg')
#=>"http://assets1.my-awesome-domain.com/images/hostsexypicture.jpg"
# File lib/merb-assets/assets_mixin.rb, line 684
def uniq_path(*assets)
  paths = []
  assets.flatten.each do |filename|
    paths.push(Merb::Assets::UniqueAssetPath.build(filename))
  end
  paths.length > 1 ? paths : paths.first
end

Private Instance Methods

append_query_string(path, random, timestamp, allow_default = true) click to toggle source
# File lib/merb-assets/assets_mixin.rb, line 785
def append_query_string(path, random, timestamp, allow_default = true)
  random = AssetsMixin.append_random_query_string?(random, allow_default)
  timestamp = AssetsMixin.append_timestamp_query_string?(timestamp, allow_default) 

  query_string = if random
                   random_query_string
                 elsif timestamp
                   timestamp == true ? timestamp_for_asset(path) : timestamp
                 end

  if query_string
    path + (path.include?('?') ? "&#{query_string}" : "?#{query_string}")
  else
    path
  end
end
extract_required_files(files, options = {}) click to toggle source

Helper method to filter out duplicate files.

Parameters

options<Hash>

Options to pass to include tag methods.

# File lib/merb-assets/assets_mixin.rb, line 770
def extract_required_files(files, options = {})
  return [] if files.nil? || files.empty?
  seen = []
  files.inject([]) do |extracted, req_js|
    include_files, include_options = if req_js.last.is_a?(Hash)
      [req_js[0..-2], options.merge(req_js.last)]
    else
      [req_js, options]
    end
    seen += (includes = include_files - seen)
    extracted << (includes + [include_options]) unless includes.empty?
    extracted
  end
end
random_query_string() click to toggle source
# File lib/merb-assets/assets_mixin.rb, line 802
def random_query_string
  Time.now.strftime("%m%d%H%M%S#{rand(99)}")
end
timestamp_for_asset(path) click to toggle source
# File lib/merb-assets/assets_mixin.rb, line 806
def timestamp_for_asset(path)
  if path !~ ABSOLUTE_PATH_REGEXP
    begin
      File.mtime(Merb.dir_for(:public) / path).to_i
    rescue
      Merb.logger.warn "#{self.class}: Unable to get mtime for #{path}"
    end 
  end
end

External JavaScript and Stylesheets

↑ top

JavaScript related functions

↑ top

Public Instance Methods

escape_js(javascript) click to toggle source

Parameters

javascript<String>

Text to escape for use in JavaScript.

Examples

escape_js("'Lorem ipsum!' -- Some guy")
  # => "\\'Lorem ipsum!\\' -- Some guy"

escape_js("Please keep text\nlines as skinny\nas possible.")
  # => "Please keep text\\nlines as skinny\\nas possible."
# File lib/merb-assets/assets_mixin.rb, line 211
def escape_js(javascript)
  (javascript || '').gsub('\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
end
js(data) click to toggle source

Parameters

data<Object>

Object to translate into JSON. If the object does not respond to :to_json, then data.inspect.to_json is returned instead.

Examples

js({'user' => 'Lewis', 'page' => 'home'})
 # => "{\"user\":\"Lewis\",\"page\":\"home\"}"

js([ 1, 2, {"a"=>3.141}, false, true, nil, 4..10 ])
  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
# File lib/merb-assets/assets_mixin.rb, line 226
def js(data)
  if data.respond_to? :to_json
    data.to_json
  else
    data.inspect.to_json
  end
end