aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers
diff options
context:
space:
mode:
authorPablo Ifran <pabloifran@gmail.com>2012-10-22 09:42:42 -0200
committerPablo Ifran <pabloifran@gmail.com>2012-10-22 09:42:42 -0200
commite041a50f2917f82950f9e5666f966d8992afd45d (patch)
tree9f4d2e3aa88f28dba9d7a1d24d46977e0642a1eb /actionpack/lib/action_view/helpers
parent3e6b2f5d38e0f31db3fb0fcd3bbab92666a0e3e2 (diff)
parentae27acb342c575ce19d5ad78cb13ba23f826fab1 (diff)
downloadrails-e041a50f2917f82950f9e5666f966d8992afd45d.tar.gz
rails-e041a50f2917f82950f9e5666f966d8992afd45d.tar.bz2
rails-e041a50f2917f82950f9e5666f966d8992afd45d.zip
Merge branch 'master' of https://github.com/lifo/docrails
Conflicts: activerecord/lib/active_record/callbacks.rb
Diffstat (limited to 'actionpack/lib/action_view/helpers')
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb358
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb93
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb70
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb71
-rw-r--r--actionpack/lib/action_view/helpers/asset_url_helper.rb355
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb9
-rw-r--r--actionpack/lib/action_view/helpers/tags/check_box.rb8
7 files changed, 448 insertions, 516 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 5b5fc84e90..31316fcdd9 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,8 +1,6 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
-require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/asset_paths'
+require 'action_view/helpers/asset_url_helper'
require 'action_view/helpers/tag_helper'
module ActionView
@@ -17,187 +15,87 @@ module ActionView
# stylesheet_link_tag("application")
# # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
#
- #
- # === 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 asset
- # server by setting <tt>ActionController::Base.asset_host</tt> 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, inside the <tt>configure</tt> block of your environment-specific
- # configuration files or <tt>config/application.rb</tt>:
- #
- # config.action_controller.asset_host = "assets.example.com"
- #
- # Helpers take that into account:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # 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 alt="Rails" src="http://assets0.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # 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
- # +asset_host+ to a proc like this:
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # The example above generates "http://assets1.example.com" and
- # "http://assets2.example.com". 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, for example "/assets/rails.png".
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # if source.ends_with?('.css')
- # "http://stylesheets.example.com"
- # else
- # "http://assets.example.com"
- # end
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # 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.
- #
- # config.action_controller.asset_host = Proc.new { |source, request|
- # if request.ssl?
- # "#{request.protocol}#{request.host_with_port}"
- # else
- # "#{request.protocol}assets.example.com"
- # end
- # }
- #
- # 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"
- # )
- #
- # === Customizing the asset path
- #
- # 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:
- #
- # # 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 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.
- #
- # This strategy works well enough for most server setups and requires the
- # least configuration, but if you deploy several application servers at
- # different times - say to handle a temporary spike in load - then the
- # asset time stamps will be out of sync. In a setup like this you may want
- # to set the way that asset paths are generated yourself.
- #
- # Altering the asset paths that Rails generates can be done in two ways.
- # The easiest is to define the RAILS_ASSET_ID environment variable. The
- # contents of this variable will always be used in preference to
- # calculated timestamps. A more complex but flexible way is to set
- # <tt>ActionController::Base.config.asset_path</tt> to a proc
- # that takes the unmodified asset path and returns the path needed for
- # your asset caching to work. Typically you'd do something like this in
- # <tt>config/environments/production.rb</tt>:
- #
- # # Normally you'd calculate RELEASE_NUMBER at startup.
- # RELEASE_NUMBER = 12345
- # config.action_controller.asset_path = proc { |asset_path|
- # "/release-#{RELEASE_NUMBER}#{asset_path}"
- # }
- #
- # This example would cause the following behavior on all servers no
- # matter when they were deployed:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="/release-12345/images/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" />
- #
- # Changing the asset_path does require that your web servers have
- # knowledge of the asset template paths that you rewrite to so it's not
- # suitable for out-of-the-box use. To use the example given above you
- # could use something like this in your Apache VirtualHost configuration:
- #
- # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$">
- # # Some browsers still send conditional-GET requests if there's a
- # # Last-Modified header or an ETag header even if they haven't
- # # reached the expiry date sent in the Expires header.
- # Header unset Last-Modified
- # Header unset ETag
- # FileETag None
- #
- # # Assets requested using a cache-busting filename should be served
- # # only once and then cached for a really long time. The HTTP/1.1
- # # spec frowns on hugely-long expiration times though and suggests
- # # that assets which never expire be served with an expiration date
- # # 1 year from access.
- # ExpiresActive On
- # ExpiresDefault "access plus 1 year"
- # </LocationMatch>
- #
- # # We use cached-busting location names with the far-future expires
- # # headers to ensure that if a file does change it can force a new
- # # request. The actual asset filenames are still the same though so we
- # # need to rewrite the location from the cache-busting location to the
- # # real asset location so that we can serve it.
- # RewriteEngine On
- # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
+ extend ActiveSupport::Concern
+
+ include AssetUrlHelper
include TagHelper
- include JavascriptTagHelpers
- include StylesheetTagHelpers
+
+ # Returns an HTML script tag for each of the +sources+ provided.
+ #
+ # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
+ # to <tt>assets/javascripts</tt>, full paths are assumed to be relative to the document
+ # root. Relative paths are idiomatic, use absolute paths only when needed.
+ #
+ # When passing paths, the ".js" extension is optional.
+ #
+ # You can modify the HTML attributes of the script tag by passing a hash as the
+ # last argument.
+ #
+ # javascript_include_tag "xmlhr"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "xmlhr.js"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "common.javascript", "/elsewhere/cools"
+ # # => <script src="/assets/common.javascript?1284139606"></script>
+ # # <script src="/elsewhere/cools.js?1423139606"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr"
+ # # => <script src="http://www.example.com/xmlhr"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr.js"
+ # # => <script src="http://www.example.com/xmlhr.js"></script>
+ #
+ def javascript_include_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "src" => path_to_javascript(source)
+ }.merge(options)
+ content_tag(:script, "", tag_options)
+ }.join("\n").html_safe
+ end
+
+ # Returns a stylesheet link tag for the sources specified as arguments. If
+ # you don't specify an extension, <tt>.css</tt> will be appended automatically.
+ # You can modify the link attributes by passing a hash as the last argument.
+ # For historical reasons, the 'media' attribute will always be present and defaults
+ # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
+ # apply to all media types.
+ #
+ # stylesheet_link_tag "style"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style.css"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "http://www.example.com/style.css"
+ # # => <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "all"
+ # # => <link href="/assets/style.css" media="all" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "print"
+ # # => <link href="/assets/style.css" media="print" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "random.styles", "/css/stylish"
+ # # => <link href="/assets/random.styles" media="screen" rel="stylesheet" />
+ # # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
+ #
+ def stylesheet_link_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "rel" => "stylesheet",
+ "media" => "screen",
+ "href" => path_to_stylesheet(source)
+ }.merge(options)
+ tag(:link, tag_options)
+ }.join("\n").html_safe
+ end
+
# Returns a link tag that browsers and news readers can use to auto-detect
# an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or
# <tt>:atom</tt>. Control the link options in url_for format using the
@@ -268,93 +166,6 @@ module ActionView
}.merge(options.symbolize_keys))
end
- # Computes the path to an image asset.
- # Full paths from the document root will be passed through.
- # Used internally by +image_tag+ to build the image path:
- #
- # image_path("edit") # => "/assets/edit"
- # image_path("edit.png") # => "/assets/edit.png"
- # image_path("icons/edit.png") # => "/assets/icons/edit.png"
- # image_path("/icons/edit.png") # => "/icons/edit.png"
- # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
- #
- # If you have images as application resources this method may conflict with their named routes.
- # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
- # plugin authors are encouraged to do so.
- def image_path(source)
- source.present? ? asset_paths.compute_public_path(source, 'images') : ""
- end
- alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
-
- # Computes the full URL to an image asset.
- # This will use +image_path+ internally, so most of their behaviors will be the same.
- def image_url(source)
- URI.join(current_host, path_to_image(source)).to_s
- end
- alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
-
- # Computes the path to a video asset in the public videos directory.
- # Full paths from the document root will be passed through.
- # Used internally by +video_tag+ to build the video path.
- #
- # video_path("hd") # => /videos/hd
- # video_path("hd.avi") # => /videos/hd.avi
- # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
- # video_path("/trailers/hd.avi") # => /trailers/hd.avi
- # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
- def video_path(source)
- asset_paths.compute_public_path(source, 'videos')
- end
- alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
-
- # Computes the full URL to a video asset in the public videos directory.
- # This will use +video_path+ internally, so most of their behaviors will be the same.
- def video_url(source)
- URI.join(current_host, path_to_video(source)).to_s
- end
- alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
-
- # Computes the path to an audio asset in the public audios directory.
- # Full paths from the document root will be passed through.
- # Used internally by +audio_tag+ to build the audio path.
- #
- # audio_path("horse") # => /audios/horse
- # audio_path("horse.wav") # => /audios/horse.wav
- # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
- # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
- # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
- def audio_path(source)
- asset_paths.compute_public_path(source, 'audios')
- end
- alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
-
- # Computes the full URL to an audio asset in the public audios directory.
- # This will use +audio_path+ internally, so most of their behaviors will be the same.
- def audio_url(source)
- URI.join(current_host, path_to_audio(source)).to_s
- end
- alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route
-
- # Computes the path to a font asset.
- # Full paths from the document root will be passed through.
- #
- # font_path("font") # => /assets/font
- # font_path("font.ttf") # => /assets/font.ttf
- # font_path("dir/font.ttf") # => /assets/dir/font.ttf
- # font_path("/dir/font.ttf") # => /dir/font.ttf
- # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
- def font_path(source)
- asset_paths.compute_public_path(source, 'fonts')
- end
- alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
-
- # Computes the full URL to a font asset.
- # This will use +font_path+ internally, so most of their behaviors will be the same.
- def font_url(source)
- URI.join(current_host, path_to_font(source)).to_s
- end
- alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
-
# Returns an html image tag for the +source+. The +source+ can be a full
# path or a file.
#
@@ -462,11 +273,6 @@ module ActionView
end
private
-
- def asset_paths
- @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller)
- end
-
def multiple_sources_tag(type, sources)
options = sources.extract_options!.symbolize_keys
sources.flatten!
@@ -482,10 +288,6 @@ module ActionView
content_tag(type, nil, options)
end
end
-
- def current_host
- url_for(:only_path => false)
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
deleted file mode 100644
index 35f91cec18..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'thread'
-require 'active_support/core_ext/file'
-require 'active_support/core_ext/module/attribute_accessors'
-
-module ActionView
- module Helpers
- module AssetTagHelper
-
- class AssetPaths < ::ActionView::AssetPaths #:nodoc:
- # You can enable or disable the asset tag ids cache.
- # With the cache enabled, the asset tag helper methods will make fewer
- # expensive file system calls (the default implementation checks the file
- # system timestamp). However this prevents you from modifying any asset
- # files while the server is running.
- #
- # ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false
- mattr_accessor :cache_asset_ids
-
- # Add or change an asset id in the asset id cache. This can be used
- # for SASS on Heroku.
- # :api: public
- def add_to_asset_ids_cache(source, asset_id)
- self.asset_ids_cache_guard.synchronize do
- self.asset_ids_cache[source] = asset_id
- end
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- source_ext = File.extname(source)
-
- source_with_ext = if source_ext.empty?
- "#{source}.#{ext}"
- elsif ext != source_ext[1..-1]
- with_ext = "#{source}.#{ext}"
- with_ext if File.exist?(File.join(config.assets_dir, dir, with_ext))
- end
-
- source_with_ext || source
- end
-
- # Break out the asset path rewrite in case plugins wish to put the asset id
- # someplace other than the query string.
- def rewrite_asset_path(source, dir, options = nil)
- source = "/#{dir}/#{source}" unless source[0] == ?/
- path = config.asset_path
-
- if path && path.respond_to?(:call)
- return path.call(source)
- elsif path && path.is_a?(String)
- return path % [source]
- end
-
- asset_id = rails_asset_id(source)
- if asset_id.empty?
- source
- else
- "#{source}?#{asset_id}"
- end
- end
-
- mattr_accessor :asset_ids_cache
- self.asset_ids_cache = {}
-
- mattr_accessor :asset_ids_cache_guard
- self.asset_ids_cache_guard = Mutex.new
-
- # Use the RAILS_ASSET_ID environment variable or the source's
- # modification time as its cache-busting asset id.
- def rails_asset_id(source)
- if asset_id = ENV["RAILS_ASSET_ID"]
- asset_id
- else
- if self.cache_asset_ids && (asset_id = self.asset_ids_cache[source])
- asset_id
- else
- path = File.join(config.assets_dir, source)
- asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : ''
-
- if self.cache_asset_ids
- add_to_asset_ids_cache(source, asset_id)
- end
-
- asset_id
- end
- end
- end
- end
-
- end
- end
-end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
deleted file mode 100644
index b6b9eadc88..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module JavascriptTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a javascript asset in the public javascripts directory.
- # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
- # Full paths from the document root will be passed through.
- # Used internally by javascript_include_tag to build the script path.
- #
- # javascript_path "xmlhr" # => /javascripts/xmlhr.js
- # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
- # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
- # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
- # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
- def javascript_path(source)
- asset_paths.compute_public_path(source, 'javascripts', :ext => 'js')
- end
- alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
-
- # Computes the full URL to a javascript asset in the public javascripts directory.
- # This will use +javascript_path+ internally, so most of their behaviors will be the same.
- def javascript_url(source)
- URI.join(current_host, path_to_javascript(source)).to_s
- end
- alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
-
- # Returns an HTML script tag for each of the +sources+ provided.
- #
- # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
- # to <tt>public/javascripts</tt>, full paths are assumed to be relative to the document
- # root. Relative paths are idiomatic, use absolute paths only when needed.
- #
- # When passing paths, the ".js" extension is optional.
- #
- # You can modify the HTML attributes of the script tag by passing a hash as the
- # last argument.
- #
- # javascript_include_tag "xmlhr"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "xmlhr.js"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "common.javascript", "/elsewhere/cools"
- # # => <script src="/javascripts/common.javascript?1284139606"></script>
- # # <script src="/elsewhere/cools.js?1423139606"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr"
- # # => <script src="http://www.example.com/xmlhr"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr.js"
- # # => <script src="http://www.example.com/xmlhr.js"></script>
- #
- def javascript_include_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.dup.map { |source|
- tag_options = {
- "src" => path_to_javascript(source)
- }.merge(options)
- content_tag(:script, "", tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
deleted file mode 100644
index bf59f8e81a..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module StylesheetTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a stylesheet asset in the public stylesheets directory.
- # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
- # Full paths from the document root will be passed through.
- # Used internally by +stylesheet_link_tag+ to build the stylesheet path.
- #
- # stylesheet_path "style" # => /stylesheets/style.css
- # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
- # stylesheet_path "/dir/style.css" # => /dir/style.css
- # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
- # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
- def stylesheet_path(source)
- asset_paths.compute_public_path(source, 'stylesheets', :ext => 'css', :protocol => :request)
- end
- alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
-
- # Computes the full URL to a stylesheet asset in the public stylesheets directory.
- # This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
- def stylesheet_url(source)
- URI.join(current_host, path_to_stylesheet(source)).to_s
- end
- alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
-
- # Returns a stylesheet link tag for the sources specified as arguments. If
- # you don't specify an extension, <tt>.css</tt> will be appended automatically.
- # You can modify the link attributes by passing a hash as the last argument.
- # For historical reasons, the 'media' attribute will always be present and defaults
- # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
- # apply to all media types.
- #
- # stylesheet_link_tag "style" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style.css" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "http://www.example.com/style.css" # =>
- # <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "all" # =>
- # <link href="/stylesheets/style.css" media="all" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "print" # =>
- # <link href="/stylesheets/style.css" media="print" rel="stylesheet" />
- #
- # stylesheet_link_tag "random.styles", "/css/stylish" # =>
- # <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" />
- # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
- #
- def stylesheet_link_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.uniq.map { |source|
- tag_options = {
- "rel" => "stylesheet",
- "media" => "screen",
- "href" => path_to_stylesheet(source)
- }.merge(options)
- tag(:link, tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
diff --git a/actionpack/lib/action_view/helpers/asset_url_helper.rb b/actionpack/lib/action_view/helpers/asset_url_helper.rb
new file mode 100644
index 0000000000..0bb5e739bb
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/asset_url_helper.rb
@@ -0,0 +1,355 @@
+require 'zlib'
+
+module ActionView
+ # = Action View Asset URL Helpers
+ module Helpers #:nodoc:
+ # This module provides methods for generating asset paths and
+ # urls.
+ #
+ # image_path("rails.png")
+ # # => "/assets/rails.png"
+ #
+ # image_url("rails.png")
+ # # => "http://www.example.com/assets/rails.png"
+ #
+ # === 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 asset
+ # server by setting <tt>ActionController::Base.asset_host</tt> 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, inside the <tt>configure</tt> block of your environment-specific
+ # configuration files or <tt>config/application.rb</tt>:
+ #
+ # config.action_controller.asset_host = "assets.example.com"
+ #
+ # Helpers take that into account:
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # 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 alt="Rails" src="http://assets0.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # 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
+ # +asset_host+ to a proc like this:
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # The example above generates "http://assets1.example.com" and
+ # "http://assets2.example.com". 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, for example "/assets/rails.png".
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # if source.ends_with?('.css')
+ # "http://stylesheets.example.com"
+ # else
+ # "http://assets.example.com"
+ # end
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # 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.
+ #
+ # config.action_controller.asset_host = Proc.new { |source, request|
+ # if request.ssl?
+ # "#{request.protocol}#{request.host_with_port}"
+ # else
+ # "#{request.protocol}assets.example.com"
+ # end
+ # }
+ #
+ # 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"
+ # )
+ #
+ module AssetUrlHelper
+ URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
+
+ # Computes the path to asset in public directory. If :type
+ # options is set, a file extension will be appended and scoped
+ # to the corresponding public directory.
+ #
+ # All other asset *_path helpers delegate through this method.
+ #
+ # asset_path "application.js" # => /application.js
+ # asset_path "application", type: :javascript # => /javascripts/application.js
+ # asset_path "application", type: :stylesheet # => /stylesheets/application.css
+ # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ def asset_path(source, options = {})
+ source = source.to_s
+ return "" unless source.present?
+ return source if source =~ URI_REGEXP
+
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '')
+
+ if extname = compute_asset_extname(source, options)
+ source = "#{source}#{extname}"
+ end
+
+ if source[0] != ?/
+ source = compute_asset_path(source, options)
+ end
+
+ relative_url_root = (defined?(config.relative_url_root) && config.relative_url_root) ||
+ (respond_to?(:request) && request.try(:script_name))
+ if relative_url_root
+ source = "#{relative_url_root}#{source}" unless source.starts_with?("#{relative_url_root}/")
+ end
+
+ if host = compute_asset_host(source, options)
+ source = "#{host}#{source}"
+ end
+
+ "#{source}#{tail}"
+ end
+ alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with a asset_path named route
+
+ # Computes the full URL to a asset in the public directory. This
+ # will use +asset_path+ internally, so most of their behaviors
+ # will be the same.
+ def asset_url(source, options = {})
+ path_to_asset(source, options.merge(:protocol => :request))
+ end
+ alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route
+
+ ASSET_EXTENSIONS = {
+ javascript: '.js',
+ stylesheet: '.css'
+ }
+
+ # Compute extname to append to asset path. Returns nil if
+ # nothing should be added.
+ def compute_asset_extname(source, options = {})
+ return if options[:extname] == false
+ extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
+ extname if extname && File.extname(source) != extname
+ end
+
+ # Maps asset types to public directory.
+ ASSET_PUBLIC_DIRECTORIES = {
+ audio: '/audios',
+ font: '/fonts',
+ image: '/images',
+ javascript: '/javascripts',
+ stylesheet: '/stylesheets',
+ video: '/videos'
+ }
+
+ # Computes asset path to public directory. Plugins and
+ # extensions can override this method to point to custom assets
+ # or generate digested paths or query strings.
+ def compute_asset_path(source, options = {})
+ dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
+ File.join(dir, source)
+ end
+
+ # Pick an asset host for this source. Returns +nil+ if no host is set,
+ # the host if no wildcard is set, the host interpolated with the
+ # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
+ # or the value returned from invoking call on an object responding to call
+ # (proc or otherwise).
+ def compute_asset_host(source = "", options = {})
+ request = self.request if respond_to?(:request)
+ host = config.asset_host if defined? config.asset_host
+ host ||= request.base_url if request && options[:protocol] == :request
+ return unless host
+
+ if host.respond_to?(:call)
+ arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
+ args = [source]
+ args << request if request && (arity > 1 || arity < 0)
+ host = host.call(*args)
+ elsif host =~ /%d/
+ host = host % (Zlib.crc32(source) % 4)
+ end
+
+ if host =~ URI_REGEXP
+ host
+ else
+ protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
+ case protocol
+ when :relative
+ "//#{host}"
+ when :request
+ "#{request.protocol}#{host}"
+ else
+ "#{protocol}://#{host}"
+ end
+ end
+ end
+
+ # Computes the path to a javascript asset in the public javascripts directory.
+ # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
+ # Full paths from the document root will be passed through.
+ # Used internally by javascript_include_tag to build the script path.
+ #
+ # javascript_path "xmlhr" # => /javascripts/xmlhr.js
+ # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
+ # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
+ # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
+ # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ def javascript_path(source, options = {})
+ path_to_asset(source, {type: :javascript}.merge!(options))
+ end
+ alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
+
+ # Computes the full URL to a javascript asset in the public javascripts directory.
+ # This will use +javascript_path+ internally, so most of their behaviors will be the same.
+ def javascript_url(source, options = {})
+ url_to_asset(source, {type: :javascript}.merge!(options))
+ end
+ alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
+
+ # Computes the path to a stylesheet asset in the public stylesheets directory.
+ # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
+ # Full paths from the document root will be passed through.
+ # Used internally by +stylesheet_link_tag+ to build the stylesheet path.
+ #
+ # stylesheet_path "style" # => /stylesheets/style.css
+ # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
+ # stylesheet_path "/dir/style.css" # => /dir/style.css
+ # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
+ # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
+ def stylesheet_path(source, options = {})
+ path_to_asset(source, {type: :stylesheet}.merge!(options))
+ end
+ alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
+
+ # Computes the full URL to a stylesheet asset in the public stylesheets directory.
+ # This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
+ def stylesheet_url(source, options = {})
+ url_to_asset(source, {type: :stylesheet}.merge!(options))
+ end
+ alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
+
+ # Computes the path to an image asset.
+ # Full paths from the document root will be passed through.
+ # Used internally by +image_tag+ to build the image path:
+ #
+ # image_path("edit") # => "/assets/edit"
+ # image_path("edit.png") # => "/assets/edit.png"
+ # image_path("icons/edit.png") # => "/assets/icons/edit.png"
+ # image_path("/icons/edit.png") # => "/icons/edit.png"
+ # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
+ #
+ # If you have images as application resources this method may conflict with their named routes.
+ # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
+ # plugin authors are encouraged to do so.
+ def image_path(source, options = {})
+ path_to_asset(source, {type: :image}.merge!(options))
+ end
+ alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
+
+ # Computes the full URL to an image asset.
+ # This will use +image_path+ internally, so most of their behaviors will be the same.
+ def image_url(source, options = {})
+ url_to_asset(source, {type: :image}.merge!(options))
+ end
+ alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
+
+ # Computes the path to a video asset in the public videos directory.
+ # Full paths from the document root will be passed through.
+ # Used internally by +video_tag+ to build the video path.
+ #
+ # video_path("hd") # => /videos/hd
+ # video_path("hd.avi") # => /videos/hd.avi
+ # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
+ # video_path("/trailers/hd.avi") # => /trailers/hd.avi
+ # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
+ def video_path(source, options = {})
+ path_to_asset(source, {type: :video}.merge!(options))
+ end
+ alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
+
+ # Computes the full URL to a video asset in the public videos directory.
+ # This will use +video_path+ internally, so most of their behaviors will be the same.
+ def video_url(source, options = {})
+ url_to_asset(source, {type: :video}.merge!(options))
+ end
+ alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
+
+ # Computes the path to an audio asset in the public audios directory.
+ # Full paths from the document root will be passed through.
+ # Used internally by +audio_tag+ to build the audio path.
+ #
+ # audio_path("horse") # => /audios/horse
+ # audio_path("horse.wav") # => /audios/horse.wav
+ # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
+ # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
+ # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
+ def audio_path(source, options = {})
+ path_to_asset(source, {type: :audio}.merge!(options))
+ end
+ alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
+
+ # Computes the full URL to an audio asset in the public audios directory.
+ # This will use +audio_path+ internally, so most of their behaviors will be the same.
+ def audio_url(source, options = {})
+ url_to_asset(source, {type: :audio}.merge!(options))
+ end
+ alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route
+
+ # Computes the path to a font asset.
+ # Full paths from the document root will be passed through.
+ #
+ # font_path("font") # => /assets/font
+ # font_path("font.ttf") # => /assets/font.ttf
+ # font_path("dir/font.ttf") # => /assets/dir/font.ttf
+ # font_path("/dir/font.ttf") # => /dir/font.ttf
+ # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
+ def font_path(source, options = {})
+ path_to_asset(source, {type: :font}.merge!(options))
+ end
+ alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
+
+ # Computes the full URL to a font asset.
+ # This will use +font_path+ internally, so most of their behaviors will be the same.
+ def font_url(source, options = {})
+ url_to_asset(source, {type: :font}.merge!(options))
+ end
+ alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 387dfeab17..f43d20c6ed 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -73,13 +73,17 @@ module ActionView
options[:include_seconds] ||= !!include_seconds_or_options
end
+ options = {
+ scope: :'datetime.distance_in_words'
+ }.merge!(options)
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
from_time, to_time = to_time, from_time if from_time > to_time
distance_in_minutes = ((to_time - from_time)/60.0).round
distance_in_seconds = (to_time - from_time).round
- I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
+ I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
case distance_in_minutes
when 0..1
return distance_in_minutes == 0 ?
@@ -196,6 +200,8 @@ module ActionView
# for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
# Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
# or the given prompt string.
+ # * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
+ # automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
@@ -937,6 +943,7 @@ module ActionView
:name => input_name_from_type(type)
}.merge!(@html_options)
select_options[:disabled] = 'disabled' if @options[:disabled]
+ select_options[:class] = type if @options[:with_css_classes]
select_html = "\n"
select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb
index 9d17a1dde3..e21cc07746 100644
--- a/actionpack/lib/action_view/helpers/tags/check_box.rb
+++ b/actionpack/lib/action_view/helpers/tags/check_box.rb
@@ -46,10 +46,12 @@ module ActionView
false
when String
value == @checked_value
- when Array
- value.include?(@checked_value)
else
- value.to_i == @checked_value.to_i
+ if value.respond_to?(:include?)
+ value.include?(@checked_value)
+ else
+ value.to_i == @checked_value.to_i
+ end
end
end