aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers
diff options
context:
space:
mode:
authorYehuda Katz <wycats@gmail.com>2009-01-30 10:53:14 -0800
committerYehuda Katz <wycats@gmail.com>2009-01-30 10:53:19 -0800
commitda10673e32718d6a0619bd0f4b4d3d796db86a1a (patch)
tree7bdb7868b0be65daec06ba729f68deccfe61a8bb /actionpack/lib/action_view/helpers
parentb8fadd708b9850a77e1f64038763fffcff502499 (diff)
parented0e5640879fd42c00fc5900e0355a0ea1dcf2ad (diff)
downloadrails-da10673e32718d6a0619bd0f4b4d3d796db86a1a.tar.gz
rails-da10673e32718d6a0619bd0f4b4d3d796db86a1a.tar.bz2
rails-da10673e32718d6a0619bd0f4b4d3d796db86a1a.zip
Sync 'rails/rails/master'
Diffstat (limited to 'actionpack/lib/action_view/helpers')
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb124
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb59
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb45
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb2
5 files changed, 166 insertions, 74 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 58f8cca6be..f6abea38ed 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -6,54 +6,70 @@ module ActionView
module Helpers #:nodoc:
# This module provides methods for generating HTML that links views to assets such
# as images, javascripts, stylesheets, and feeds. These methods do not verify
- # the assets exist before linking to them.
+ # the assets exist before linking to them:
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails src="/images/rails.png?1230601161" />
+ # stylesheet_link_tag("application")
+ # # => <link href="/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
# === Using asset hosts
+ #
# By default, Rails links to these assets on the current host in the public
- # folder, but you can direct Rails to link to assets from a dedicated assets server by
- # setting ActionController::Base.asset_host in your <tt>config/environment.rb</tt>. For example,
- # let's say your asset host is <tt>assets.example.com</tt>.
+ # folder, but you can direct Rails to link to assets from a dedicated asset
+ # server by setting ActionController::Base.asset_host in the application
+ # configuration, typically in <tt>config/environments/production.rb</tt>.
+ # For example, you'd define <tt>assets.example.com</tt> to be your asset
+ # host this way:
#
# ActionController::Base.asset_host = "assets.example.com"
+ #
+ # Helpers take that into account:
+ #
# image_tag("rails.png")
- # => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
+ # # => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
# stylesheet_link_tag("application")
- # => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
+ # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
- # This is useful since browsers typically open at most two connections to a single host,
- # which means your assets often wait in single file for their turn to load. You can
- # alleviate this by using a <tt>%d</tt> wildcard in <tt>asset_host</tt> (for example, "assets%d.example.com")
- # to automatically distribute asset requests among four hosts (e.g., "assets0.example.com" through "assets3.example.com")
- # so browsers will open eight connections rather than two.
+ # Browsers typically open at most two simultaneous connections to a single
+ # host, which means your assets often have to wait for other assets to finish
+ # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
+ # +asset_host+. For example, "assets%d.example.com". If that wildcard is
+ # present Rails distributes asset requests among the corresponding four hosts
+ # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
+ # will open eight simultaneous connections rather than two.
#
# image_tag("rails.png")
- # => <img src="http://assets0.example.com/images/rails.png" alt="Rails" />
+ # # => <img alt="Rails" src="http://assets0.example.com/images/rails.png?1230601161" />
# stylesheet_link_tag("application")
- # => <link href="http://assets3.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
+ # # => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
- # To do this, you can either setup 4 actual hosts, or you can use wildcard DNS to CNAME
- # the wildcard to a single asset host. You can read more about setting up your DNS CNAME records from
- # your ISP.
+ # To do this, you can either setup four actual hosts, or you can use wildcard
+ # DNS to CNAME the wildcard to a single asset host. You can read more about
+ # setting up your DNS CNAME records from your ISP.
#
# Note: This is purely a browser performance optimization and is not meant
# for server load balancing. See http://www.die.net/musings/page_load_time/
# for background.
#
- # Alternatively, you can exert more control over the asset host by setting <tt>asset_host</tt> to a proc
- # that takes a single source argument. This is useful if you are unable to setup 4 actual hosts or have
- # fewer/more than 4 hosts. The example proc below generates http://assets1.example.com and
- # http://assets2.example.com randomly.
+ # Alternatively, you can exert more control over the asset host by setting
+ # +asset_host+ to a proc like this:
#
- # ActionController::Base.asset_host = Proc.new { |source| "http://assets#{rand(2) + 1}.example.com" }
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # "http://assets#{rand(2) + 1}.example.com"
+ # }
# image_tag("rails.png")
- # => <img src="http://assets2.example.com/images/rails.png" alt="Rails" />
+ # # => <img alt="Rails" src="http://assets0.example.com/images/rails.png?1230601161" />
# stylesheet_link_tag("application")
- # => <link href="http://assets1.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
+ # # => <link href="http://assets1.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
- # The proc takes a <tt>source</tt> parameter (which is the path of the source asset) and an optional
- # <tt>request</tt> parameter (which is an entire instance of an <tt>ActionController::AbstractRequest</tt>
- # subclass). This can be used to generate a particular asset host depending on the asset path and the particular
- # request.
+ # The example above generates "http://assets1.example.com" and
+ # "http://assets2.example.com" randomly. This option is useful for example if
+ # you need fewer/more than four hosts, custom host names, etc.
+ #
+ # As you see the proc takes a +source+ parameter. That's a string with the
+ # absolute path of the asset with any extensions and timestamps in place,
+ # for example "/images/rails.png?1230601161".
#
# ActionController::Base.asset_host = Proc.new { |source|
# if source.starts_with?('/images')
@@ -63,14 +79,16 @@ module ActionView
# end
# }
# image_tag("rails.png")
- # => <img src="http://images.example.com/images/rails.png" alt="Rails" />
+ # # => <img alt="Rails" src="http://images.example.com/images/rails.png?1230601161" />
# stylesheet_link_tag("application")
- # => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
+ # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
#
- # The optional <tt>request</tt> parameter to the proc is useful in particular for serving assets from an
- # SSL-protected page. The example proc below disables asset hosting for HTTPS connections, while still sending
- # assets for plain HTTP requests from asset hosts. This is useful for avoiding mixed media warnings when serving
- # non-HTTP assets from HTTPS web pages when you don't have an SSL certificate for each of the asset hosts.
+ # Alternatively you may ask for a second parameter +request+. That one is
+ # particularly useful for serving assets from an SSL-protected page. The
+ # example proc below disables asset hosting for HTTPS connections, while
+ # still sending assets for plain HTTP requests from asset hosts. If you don't
+ # have SSL certificates for each of the asset hosts this technique allows you
+ # to avoid warnings in the client about mixed media.
#
# ActionController::Base.asset_host = Proc.new { |source, request|
# if request.ssl?
@@ -80,7 +98,8 @@ module ActionView
# end
# }
#
- # You can also implement a custom asset host object that responds to the call method and tasks one or two parameters just like the proc.
+ # You can also implement a custom asset host object that responds to +call+
+ # and takes either one or two parameters just like the proc.
#
# config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
# "http://asset%d.example.com", "https://asset1.example.com"
@@ -88,24 +107,29 @@ module ActionView
#
# === Using asset timestamps
#
- # By default, Rails will append all asset paths with that asset's timestamp. This allows you to set a cache-expiration date for the
- # asset far into the future, but still be able to instantly invalidate it by simply updating the file (and hence updating the timestamp,
- # which then updates the URL as the timestamp is part of that, which in turn busts the cache).
+ # By default, Rails appends asset's timestamps to all asset paths. This allows
+ # you to set a cache-expiration date for the asset far into the future, but
+ # still be able to instantly invalidate it by simply updating the file (and
+ # hence updating the timestamp, which then updates the URL as the timestamp
+ # is part of that, which in turn busts the cache).
#
- # It's the responsibility of the web server you use to set the far-future expiration date on cache assets that you need to take
- # advantage of this feature. Here's an example for Apache:
+ # It's the responsibility of the web server you use to set the far-future
+ # expiration date on cache assets that you need to take advantage of this
+ # feature. Here's an example for Apache:
#
- # # Asset Expiration
- # ExpiresActive On
- # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
- # ExpiresDefault "access plus 1 year"
- # </FilesMatch>
+ # # Asset Expiration
+ # ExpiresActive On
+ # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
+ # ExpiresDefault "access plus 1 year"
+ # </FilesMatch>
#
- # Also note that in order for this to work, all your application servers must return the same timestamps. This means that they must
- # have their clocks synchronized. If one of them drift out of sync, you'll see different timestamps at random and the cache won't
- # work. Which means that the browser will request the same assets over and over again even thought they didn't change. You can use
- # something like Live HTTP Headers for Firefox to verify that the cache is indeed working (and that the assets are not being
- # requested over and over).
+ # Also note that in order for this to work, all your application servers must
+ # return the same timestamps. This means that they must have their clocks
+ # synchronized. If one of them drifts out of sync, you'll see different
+ # timestamps at random and the cache won't work. In that case the browser
+ # will request the same assets over and over again even thought they didn't
+ # change. You can use something like Live HTTP Headers for Firefox to verify
+ # that the cache is indeed working.
module AssetTagHelper
ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public"
JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts"
@@ -117,7 +141,7 @@ module ActionView
# <tt>:atom</tt>. Control the link options in url_for format using the
# +url_options+. You can modify the LINK tag itself in +tag_options+.
#
- # ==== Options:
+ # ==== Options
# * <tt>:rel</tt> - Specify the relation of this link, defaults to "alternate"
# * <tt>:type</tt> - Override the auto-generated mime type
# * <tt>:title</tt> - Specify the title of the link, defaults to the +type+
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 4305617ac8..b4c1adbe76 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -860,7 +860,7 @@ module ActionView
# => post[written_on(1i)]
def input_name_from_type(type)
prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
- prefix += "[#{@options[:index]}]" if @options[:index]
+ prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
field_name = @options[:field_name] || type
if @options[:include_position]
@@ -923,7 +923,7 @@ module ActionView
options[:field_name] = @method_name
options[:include_position] = true
options[:prefix] ||= @object_name
- options[:index] ||= @auto_index
+ options[:index] = @auto_index if @auto_index && !options.has_key?(:index)
options[:datetime_separator] ||= ' &mdash; '
options[:time_separator] ||= ' : '
@@ -961,15 +961,15 @@ module ActionView
class FormBuilder
def date_select(method, options = {}, html_options = {})
- @template.date_select(@object_name, method, options.merge(:object => @object), html_options)
+ @template.date_select(@object_name, method, objectify_options(options), html_options)
end
def time_select(method, options = {}, html_options = {})
- @template.time_select(@object_name, method, options.merge(:object => @object), html_options)
+ @template.time_select(@object_name, method, objectify_options(options), html_options)
end
def datetime_select(method, options = {}, html_options = {})
- @template.datetime_select(@object_name, method, options.merge(:object => @object), html_options)
+ @template.datetime_select(@object_name, method, objectify_options(options), html_options)
end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 9ed50a9653..54c82cbd1d 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -277,6 +277,62 @@ module ActionView
end
end
+ # Returns a string of <tt><option></tt> tags, like <tt>options_for_select</tt>, but
+ # wraps them with <tt><optgroup></tt> tags.
+ #
+ # Parameters:
+ # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
+ # <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
+ # nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
+ # Ex. ["North America",[["United States","US"],["Canada","CA"]]]
+ # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
+ # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
+ # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
+ # * +prompt+ - set to true or a prompt string. When the select element doesn’t have a value yet, this
+ # prepends an option with a generic prompt — "Please select" — or the given prompt string.
+ #
+ # Sample usage (Array):
+ # grouped_options = [
+ # ['North America',
+ # [['United States','US'],'Canada']],
+ # ['Europe',
+ # ['Denmark','Germany','France']]
+ # ]
+ # grouped_options_for_select(grouped_options)
+ #
+ # Sample usage (Hash):
+ # grouped_options = {
+ # 'North America' => [['United States','US], 'Canada'],
+ # 'Europe' => ['Denmark','Germany','France']
+ # }
+ # grouped_options_for_select(grouped_options)
+ #
+ # Possible output:
+ # <optgroup label="Europe">
+ # <option value="Denmark">Denmark</option>
+ # <option value="Germany">Germany</option>
+ # <option value="France">France</option>
+ # </optgroup>
+ # <optgroup label="North America">
+ # <option value="US">United States</option>
+ # <option value="Canada">Canada</option>
+ # </optgroup>
+ #
+ # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
+ # wrap the output in an appropriate <tt><select></tt> tag.
+ def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
+ body = ''
+ body << content_tag(:option, prompt, :value => "") if prompt
+
+ grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
+
+ grouped_options.each do |group|
+ body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0])
+ end
+
+ body
+ end
+
# Returns a string of option tags for pretty much any time zone in the
# world. Supply a TimeZone name as +selected+ to have it marked as the
# selected option tag. You can also supply an array of TimeZone objects
@@ -349,8 +405,9 @@ module ActionView
html_options = html_options.stringify_keys
add_default_name_and_id(html_options)
value = value(object)
+ selected_value = options.has_key?(:selected) ? options[:selected] : value
content_tag(
- "select", add_options(options_from_collection_for_select(collection, value_method, text_method, value), options, value), html_options
+ "select", add_options(options_from_collection_for_select(collection, value_method, text_method, selected_value), options, value), html_options
)
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 3e734ccaab..e622f97b9e 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -220,6 +220,8 @@ module ActionView
end
end
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
+
# Formats the bytes in +size+ into a more understandable representation
# (e.g., giving it 1500 yields 1.5 KB). This method is useful for
# reporting file sizes to users. This method returns nil if
@@ -247,7 +249,7 @@ module ActionView
# number_to_human_size(1234567, 2) # => 1.18 MB
# number_to_human_size(483989, 0) # => 473 KB
def number_to_human_size(number, *args)
- return number.nil? ? nil : pluralize(number.to_i, "Byte") if number.to_i < 1024
+ return nil if number.nil?
options = args.extract_options!
options.symbolize_keys!
@@ -255,7 +257,6 @@ module ActionView
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
defaults = defaults.merge(human)
- storage_units = I18n.translate(:'number.human.storage_units', :locale => options[:locale], :raise => true)
unless args.empty?
ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' +
@@ -267,22 +268,32 @@ module ActionView
separator ||= (options[:separator] || defaults[:separator])
delimiter ||= (options[:delimiter] || defaults[:delimiter])
- max_exp = storage_units.size - 1
- number = Float(number)
- exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
- exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
- number /= 1024 ** exponent
- unit = storage_units[exponent]
+ storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
- begin
- escaped_separator = Regexp.escape(separator)
- number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter
- ).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') + " #{unit}"
- rescue
- number
+ if number.to_i < 1024
+ unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
+ else
+ max_exp = STORAGE_UNITS.size - 1
+ number = Float(number)
+ exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
+ number /= 1024 ** exponent
+
+ unit_key = STORAGE_UNITS[exponent]
+ unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
+
+ begin
+ escaped_separator = Regexp.escape(separator)
+ formatted_number = number_with_precision(number,
+ :precision => precision,
+ :separator => separator,
+ :delimiter => delimiter
+ ).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
+ rescue
+ number
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 1d9e4fe9b8..b1eb6891fa 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -107,7 +107,7 @@ module ActionView
text
else
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
- text.gsub(/(#{match})/i, options[:highlighter])
+ text.gsub(/(#{match})(?!(?:[^<]*?)?(?:["'])[^<>]*>)/i, options[:highlighter])
end
end