diff options
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/action_view/helpers/asset_tag_helper.rb | 108 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/benchmark_helper.rb | 17 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/cache_helper.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/capture_helper.rb | 118 | ||||
-rwxr-xr-x | actionpack/lib/action_view/helpers/date_helper.rb | 268 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_tag_helper.rb | 299 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/number_helper.rb | 111 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/tag_helper.rb | 50 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/text_helper.rb | 266 |
9 files changed, 1005 insertions, 261 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 8b9e4094ce..6c4eb0931c 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -4,11 +4,15 @@ require 'action_view/helpers/tag_helper' module ActionView module Helpers #:nodoc: - # Provides methods for linking an HTML page together with other assets such - # as images, javascripts, stylesheets, and feeds. You can direct Rails to - # link to assets from a dedicated assets server by setting ActionController::Base.asset_host - # in your environment.rb. These methods do not verify the assets exist before - # linking to them. + # 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. + # + # === 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 environment.rb. For example, + # let's say your asset host is assets.example.com. # # ActionController::Base.asset_host = "assets.example.com" # image_tag("rails.png") @@ -16,15 +20,22 @@ module ActionView # stylesheet_include_tag("application") # => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="Stylesheet" type="text/css" /> # - # Since browsers typically open at most two connections to a single host, - # your assets often wait in single file for their turn to load. + # 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 %d 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. + # + # image_tag("rails.png") + # => <img src="http://assets0.example.com/images/rails.png" alt="Rails" /> + # stylesheet_include_tag("application") + # => <link href="http://assets3.example.com/stylesheets/application.css" media="screen" rel="Stylesheet" type="text/css" /> # - # Use a %d wildcard in asset_host (asset%d.myapp.com) to automatically - # distribute asset requests among four hosts (asset0-asset3.myapp.com) - # so browsers will open eight connections rather than two. Use wildcard - # DNS to CNAME the wildcard to your real asset host. + # 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 + # 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. module AssetTagHelper @@ -37,19 +48,24 @@ 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+. # - # Tag 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+ # + # ==== Examples # auto_discovery_link_tag # => - # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" /> + # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/action" /> # auto_discovery_link_tag(:atom) # => - # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" /> + # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.currenthost.com/controller/action" /> # auto_discovery_link_tag(:rss, {:action => "feed"}) # => - # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/feed" /> + # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/feed" /> # auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # => - # <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/controller/feed" /> + # <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.currenthost.com/controller/feed" /> + # auto_discovery_link_tag(:rss, {:controller => "news", :action => "feed"}) # => + # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/news/feed" /> + # auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "Example RSS"}) # => + # <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed" /> def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {}) tag( "link", @@ -65,9 +81,12 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by javascript_include_tag to build the script path. # + # ==== Examples # 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.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr.js + # javascript_path "http://www.railsapplication.com/js/xmlhr.js" # => http://www.railsapplication.com/js/xmlhr.js def javascript_path(source) compute_public_path(source, 'javascripts', 'js') end @@ -85,22 +104,35 @@ module ActionView # javascripts directory, it will be included as well. You can modify the # html attributes of the script tag by passing a hash as the last argument. # + # ==== Examples # javascript_include_tag "xmlhr" # => # <script type="text/javascript" src="/javascripts/xmlhr.js"></script> # + # javascript_include_tag "xmlhr.js" # => + # <script type="text/javascript" src="/javascripts/xmlhr.js"></script> + # # javascript_include_tag "common.javascript", "/elsewhere/cools" # => # <script type="text/javascript" src="/javascripts/common.javascript"></script> # <script type="text/javascript" src="/elsewhere/cools.js"></script> # + # javascript_include_tag "http://www.railsapplication.com/xmlhr" # => + # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script> + # + # javascript_include_tag "http://www.railsapplication.com/xmlhr.js" # => + # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script> + # # javascript_include_tag :defaults # => # <script type="text/javascript" src="/javascripts/prototype.js"></script> # <script type="text/javascript" src="/javascripts/effects.js"></script> # ... - # <script type="text/javascript" src="/javascripts/application.js"></script> *see below + # <script type="text/javascript" src="/javascripts/application.js"></script> <!-- * see below --> # # * = The application.js file is only referenced if it exists # - # You can also include all javascripts in the javascripts directory using :all as the source: + # Though it's not really recommended practice, if you need to extend the default JavaScript set for any reason + # (e.g., you're going to be using a certain .js file in every action), then take a look at the register_javascript_include_default method. + # + # You can also include all javascripts in the javascripts directory using <tt>:all</tt> as the source: # # javascript_include_tag :all # => # <script type="text/javascript" src="/javascripts/prototype.js"></script> @@ -110,16 +142,17 @@ module ActionView # <script type="text/javascript" src="/javascripts/shop.js"></script> # <script type="text/javascript" src="/javascripts/checkout.js"></script> # - # Note that the default javascript files will be included first. So Prototype and Scriptaculous are available for - # all subsequently included files. They + # Note that the default javascript files will be included first. So Prototype and Scriptaculous are available to + # all subsequently included files. # # == Caching multiple javascripts into one # - # You can also cache multiple javascripts into one file, which requires less HTTP connections and can better be + # You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching - # is set to true (which is the case by default for the Rails production environment, but not for the development - # environment). Examples: + # is set to <tt>true</tt> (which is the case by default for the Rails production environment, but not for the development + # environment). # + # ==== Examples # javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is false => # <script type="text/javascript" src="/javascripts/prototype.js"></script> # <script type="text/javascript" src="/javascripts/effects.js"></script> @@ -168,7 +201,7 @@ module ActionView # Register one or more additional JavaScript files to be included when # <tt>javascript_include_tag :defaults</tt> is called. This method is - # only intended to be called from plugin initialization to register additional + # typically intended to be called from plugin initialization to register additional # .js files that the plugin installed in <tt>public/javascripts</tt>. def self.register_javascript_include_default(*sources) @@javascript_default_sources.concat(sources) @@ -183,9 +216,12 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by stylesheet_link_tag to build the stylesheet path. # + # ==== Examples # 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.railsapplication.com/css/style" # => http://www.railsapplication.com/css/style.css + # stylesheet_path "http://www.railsapplication.com/css/style.js" # => http://www.railsapplication.com/css/style.css def stylesheet_path(source) compute_public_path(source, 'stylesheets', 'css') end @@ -194,12 +230,22 @@ module ActionView # you don't specify an extension, .css will be appended automatically. # You can modify the link attributes by passing a hash as the last argument. # + # ==== Examples # stylesheet_link_tag "style" # => # <link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" /> # + # stylesheet_link_tag "style.css" # => + # <link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" /> + # + # stylesheet_link_tag "http://www.railsapplication.com/style.css" # => + # <link href="http://www.railsapplication.com/style.css" media="screen" rel="Stylesheet" type="text/css" /> + # # stylesheet_link_tag "style", :media => "all" # => # <link href="/stylesheets/style.css" media="all" rel="Stylesheet" type="text/css" /> # + # stylesheet_link_tag "style", :media => "print" # => + # <link href="/stylesheets/style.css" media="print" rel="Stylesheet" type="text/css" /> + # # stylesheet_link_tag "random.styles", "/css/stylish" # => # <link href="/stylesheets/random.styles" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" /> @@ -218,6 +264,7 @@ module ActionView # is set to true (which is the case by default for the Rails production environment, but not for the development # environment). Examples: # + # ==== Examples # stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false => # <link href="/stylesheets/style1.css" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/stylesheets/styleB.css" media="screen" rel="Stylesheet" type="text/css" /> @@ -271,9 +318,11 @@ module ActionView # Used internally by image_tag to build the image path. Passing # a filename without an extension is deprecated. # + # ==== Examples # image_path("edit.png") # => /images/edit.png # image_path("icons/edit.png") # => /images/icons/edit.png # image_path("/icons/edit.png") # => /icons/edit.png + # image_path("http://www.railsapplication.com/img/edit.png") # => http://www.railsapplication.com/img/edit.png def image_path(source) unless (source.split("/").last || source).include?(".") || source.blank? ActiveSupport::Deprecation.warn( @@ -289,7 +338,9 @@ module ActionView # Returns an html image tag for the +source+. The +source+ can be a full # path or a file that exists in your public images directory. Note that # specifying a filename without the extension is now deprecated in Rails. - # You can add html attributes using the +options+. The +options+ supports + # + # ==== Options + # You can add HTML attributes using the +options+. The +options+ supports # two additional keys for convienence and conformance: # # * <tt>:alt</tt> - If no alt text is given, the file name part of the @@ -298,12 +349,17 @@ module ActionView # width="30" and height="45". <tt>:size</tt> will be ignored if the # value is not in the correct format. # + # ==== Examples # image_tag("icon.png") # => # <img src="/images/icon.png" alt="Icon" /> # image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # => # <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" /> # image_tag("/icons/icon.gif", :size => "16x16") # => # <img src="/icons/icon.gif" width="16" height="16" alt="Icon" /> + # image_tag("/icons/icon.gif", :height => '32', :width => '32') # => + # <img alt="Icon" height="32" src="/icons/icon.gif" width="32" /> + # image_tag("/icons/icon.gif", :class => "menu_icon") # => + # <img alt="Icon" class="menu_icon" src="/icons/icon.gif" /> def image_tag(source, options = {}) options.symbolize_keys! diff --git a/actionpack/lib/action_view/helpers/benchmark_helper.rb b/actionpack/lib/action_view/helpers/benchmark_helper.rb index 1d53be51db..fefa28f4d7 100644 --- a/actionpack/lib/action_view/helpers/benchmark_helper.rb +++ b/actionpack/lib/action_view/helpers/benchmark_helper.rb @@ -2,17 +2,24 @@ require 'benchmark' module ActionView module Helpers + # This helper offers a method to measure the execution time of a block + # in a template. module BenchmarkHelper - # Measures the execution time of a block in a template and reports the result to the log. Example: + # Allows you to measure the execution time of a block + # in a template and records the result to the log. Wrap this block around + # expensive operations or possible bottlenecks to get a time reading + # for the operation. For example, let's say you thought your file + # processing method was taking too long; you could wrap it in a benchmark block. # - # <% benchmark "Notes section" do %> - # <%= expensive_notes_operation %> + # <% benchmark "Process data files" do %> + # <%= expensive_files_operation %> # <% end %> # - # Will add something like "Notes section (0.34523)" to the log. + # That would add something like "Process data files (0.34523)" to the log, + # which you can then use to compare timings when optimizing your code. # # You may give an optional logger level as the second argument - # (:debug, :info, :warn, :error). The default is :info. + # (:debug, :info, :warn, :error); the default value is :info. def benchmark(message = "Benchmarking", level = :info) if @logger real = Benchmark.realtime { yield } diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index de2707ac75..cf5420a35e 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -1,7 +1,36 @@ module ActionView module Helpers + # This helper to exposes a method for caching of view fragments. # See ActionController::Caching::Fragments for usage instructions. module CacheHelper + # A method for caching fragments of a view rather than an entire + # action or page. This technique is useful caching pieces like + # menus, lists of news topics, static HTML fragments, and so on. + # This method takes a block that contains the content you wish + # to cache. See ActionController::Caching::Fragments for more + # information. + # + # ==== Examples + # If you wanted to cache a navigation menu, you could do the + # following. + # + # <% cache do %> + # <%= render :partial => "menu" %> + # <% end %> + # + # You can also cache static content... + # + # <% cache do %> + # <p>Hello users! Welcome to our website!</p> + # <% end %> + # + # ...and static content mixed with RHTML content. + # + # <% cache do %> + # Topics: + # <%= render :partial => "topics", :collection => @topic_list %> + # <i>Topics listed alphabetically</i> + # <% end %> def cache(name = {}, &block) @controller.cache_erb_fragment(block, name) end diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 91cff4f981..7cf2b02659 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -1,58 +1,36 @@ module ActionView module Helpers - # Capture lets you extract parts of code which - # can be used in other points of the template or even layout file. - # - # == Capturing a block into an instance variable - # - # <% @script = capture do %> - # [some html...] - # <% end %> - # - # == Add javascript to header using content_for - # - # content_for("name") is a wrapper for capture which will - # make the fragment available by name to a yielding layout or template. - # - # layout.erb: - # - # <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - # <head> - # <title>layout with js</title> - # <script type="text/javascript"> - # <%= yield :script %> - # </script> - # </head> - # <body> - # <%= yield %> - # </body> - # </html> - # - # view.erb - # - # This page shows an alert box! - # - # <% content_for("script") do %> - # alert('hello world') - # <% end %> - # - # Normal view text + # CaptureHelper exposes methods to let you extract generated markup which + # can be used in other parts of a template or layout file. + # It provides a method to capture blocks into variables through capture and + # a way to capture a block of code for use in a layout through content_for. module CaptureHelper - # Capture allows you to extract a part of the template into an - # instance variable. You can use this instance variable anywhere - # in your templates and even in your layout. + # The capture method allows you to extract a part of the template into a + # variable. You can then use this value anywhere in your templates or layout. # - # Example of capture being used in a .erb page: + # ==== Examples + # The capture method can be used in RHTML (ERb) templates... # # <% @greeting = capture do %> - # Welcome To my shiny new web page! + # Welcome to my shiny new web page! The date and time is + # <%= Time.now %> # <% end %> # - # Example of capture being used in a .builder page: + # ...and Builder (RXML) templates. # - # @greeting = capture do - # 'Welcome To my shiny new web page!' + # @timestamp = capture do + # "The current timestamp is #{Time.now}." # end + # + # You can then use the content as a variable anywhere else. For + # example: + # + # <html> + # <head><title><%= @greeting %></title></head> + # <body> + # <b><%= @greeting %></b> + # </body></html> + # def capture(*args, &block) # execute the block begin @@ -68,19 +46,53 @@ module ActionView end end - # Calling content_for stores the block of markup for later use. - # Subsequently, you can make calls to it by name with <tt>yield</tt> - # in another template or in the layout. + # Calling content_for stores the block of markup in an identifier for later use. + # You can make subsequent calls to the stored content in another template or in the layout + # by calling it by name with <tt>yield</tt>. # - # Example: + # ==== Examples # - # <% content_for("header") do %> - # alert('hello world') + # <% content_for("authorized") do %> + # alert('You are not authorized for that!') + # <% end %> + # + # You can then use <tt>yield :authorized</tt> anywhere in your templates. + # + # <%= yield :authorized if current_user == nil %> + # + # You can also use these variables in a layout. For example: + # + # <!-- This is the layout --> + # <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + # <head> + # <title>My Website</title> + # <%= yield :script %> + # </head> + # <body> + # <%= yield %> + # </body> + # </html> + # + # And now we'll create a view that has a content_for call that + # creates the <tt>script</tt> identifier. + # + # <!-- This is our view --> + # Please login! + # + # <% content_for("script") do %> + # <script type="text/javascript">alert('You are not authorized for this action!')</script> # <% end %> # - # You can use yield :header anywhere in your templates. + # Then in another view you may want to do something like this: + # + # <%= link_to_remote 'Logout', :action => 'logout' %> + # + # <% content_for("script") do %> + # <%= javascript_include_tag :defaults %> + # <% end %> # - # <%= yield :header %> + # That will include Prototype and Scriptaculous into the page; this technique + # is useful if you'll only be using these scripts on a few views. # # NOTE: Beware that content_for is ignored in caches. So you shouldn't use it # for elements that are going to be fragment cached. diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 6ab2596439..9903bed34d 100755 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -37,12 +37,24 @@ module ActionView # 40-59 secs # => less than a minute # 60-89 secs # => 1 minute # - # Examples: - # + # ==== Examples # from_time = Time.now - # distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour - # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute - # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds + # distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour + # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour + # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute + # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds + # distance_of_time_in_words(from_time, 3.years.from_now) # => over 3 years + # distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days + # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute + # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute + # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute + # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 years + # distance_of_time_in_words(from_time, from_time + 4.years + 15.days + 30.minutes + 5.seconds) # => over 4 years + # + # to_time = Time.now + 6.years + 19.days + # distance_of_time_in_words(from_time, to_time, true) # => over 6 years + # distance_of_time_in_words(to_time, from_time, true) # => over 6 years + # distance_of_time_in_words(Time.now, Time.now) # => less than a minute # # Note: Rails calculates one year as 365.25 days. def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false) @@ -76,6 +88,13 @@ module ActionView end # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>. + # + # ==== Examples + # time_ago_in_words(3.minutes.from_now) # => 3 minutes + # time_ago_in_words(Time.now - 15.hours) # => 15 hours + # time_ago_in_words(Time.now) # => less than a minute + # + # from_time = Time.now - 3.days - 14.minutes - 25.seconds # => 3 days def time_ago_in_words(from_time, include_seconds = false) distance_of_time_in_words(from_time, Time.now, include_seconds) end @@ -96,16 +115,34 @@ module ActionView # # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. # - # Examples: - # + # ==== Examples + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute # date_select("post", "written_on") + # + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute, + # # with the year in the year drop down box starting at 1995. # date_select("post", "written_on", :start_year => 1995) + # + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute, + # # with the year in the year drop down box starting at 1995, numbers used for months instead of words, + # # and without a day select box. # date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true, # :discard_day => true, :include_blank => true) + # + # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute + # # with the fields ordered as day, month, year rather than month, day, year. # date_select("post", "written_on", :order => [:day, :month, :year]) - # date_select("user", "birthday", :order => [:month, :day]) # + # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute + # # lacking a year field. + # date_select("user", "birthday", :order => [:month, :day]) + # + # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute + # # which is initially set to the date 3 days from the current date # date_select("post", "written_on", :default => 3.days.from_now) + # + # # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute + # # that will have a default day of 20. # date_select("credit_card", "bill_due", :default => { :day => 20 }) # # The selects are prepared for multi-parameter assignment to an Active Record object. @@ -119,11 +156,25 @@ module ActionView # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified # time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+). # You can include the seconds with <tt>:include_seconds</tt>. - # Examples: - # + # + # ==== Examples + # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute # time_select("post", "sunrise") + # + # # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute + # time_select("order", "submitted") + # + # # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute + # time_select("mail", "sent_at") + # + # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in + # # the sunrise attribute. # time_select("post", "start_time", :include_seconds => true) # + # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the entry variables in + # # the submission_time attribute. + # time_select("entry", "submission_time", :include_seconds => true) + # # The selects are prepared for multi-parameter assignment to an Active Record object. # # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month @@ -135,9 +186,22 @@ module ActionView # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based # attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples: # + # ==== Examples + # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute # datetime_select("post", "written_on") + # + # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the + # # post variable in the written_on attribute. # datetime_select("post", "written_on", :start_year => 1995) # + # # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will be stored in the + # # trip variable in the departing attribute. + # datetime_select("trip", "departing", :default => 3.days.from_now) + # + # # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable as the written_on + # # attribute. + # datetime_select("post", "written_on", :discard_type => true) + # # The selects are prepared for multi-parameter assignment to an Active Record object. def datetime_select(object_name, method, options = {}) InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options) @@ -148,7 +212,33 @@ module ActionView # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it # will be appened onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt> # keys to the +options+ to control visual display of the elements. - def select_datetime(datetime = Time.now, options = {}) + # + # ==== Examples + # my_date_time = Time.now + 4.days + # + # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today) + # select_datetime(my_date_time) + # + # # Generates a datetime select that defaults to today (no specified datetime) + # select_datetime() + # + # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today) + # # with the fields ordered year, month, day rather then month, day, year. + # select_datetime(my_date_time, :order => [:year, :month, :day]) + # + # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today) + # # with a '/' between each date field. + # select_datetime(my_date_time, :date_separator => '/') + # + # # Generates a datetime select that discards the type of the field and defaults to the datetime in + # # my_date_time (four days after today) + # select_datetime(my_date_time, :discard_type => true) + # + # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today) + # # prefixed with 'payday' rather than 'date' + # select_datetime(my_date_time, :prefix => 'payday') + # + def select_datetime(datetime = Time.now, options = {}) separator = options[:datetime_separator] || '' select_date(datetime, options) + separator + select_time(datetime, options) end @@ -157,6 +247,28 @@ module ActionView # It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it # will be appened onto the <tt>:order</tt> passed in. + # + # ==== Examples + # my_date = Time.today + 6.days + # + # # Generates a date select that defaults to the date in my_date (six days after today) + # select_date(my_date) + # + # # Generates a date select that defaults to today (no specified date) + # select_date() + # + # # Generates a date select that defaults to the date in my_date (six days after today) + # # with the fields ordered year, month, day rather then month, day, year. + # select_date(my_date, :order => [:year, :month, :day]) + # + # # Generates a date select that discards the type of the field and defaults to the date in + # # my_date (six days after today) + # select_datetime(my_date_time, :discard_type => true) + # + # # Generates a date select that defaults to the datetime in my_date (six days after today) + # # prefixed with 'payday' rather than 'date' + # select_datetime(my_date_time, :prefix => 'payday') + # def select_date(date = Date.today, options = {}) options[:order] ||= [] [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) } @@ -169,7 +281,30 @@ module ActionView end # Returns a set of html select-tags (one for hour and minute) - # You can set <tt>:add_separator</tt> key to format the output. + # You can set <tt>:time_separator</tt> key to format the output, and + # the <tt>:include_seconds</tt> option to include an input for seconds. + # + # ==== Examples + # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds + # + # # Generates a time select that defaults to the time in my_time + # select_time(my_time) + # + # # Generates a time select that defaults to the current time (no specified time) + # select_time() + # + # # Generates a time select that defaults to the time in my_time, + # # which has fields separated by ':' + # select_time(my_time, :time_separator => ':') + # + # # Generates a time select that defaults to the time in my_time, + # # that also includes an input for seconds + # select_time(my_time, :include_seconds => true) + # + # # Generates a time select that defaults to the time in my_time, that has fields + # # separated by ':' and includes an input for seconds + # select_time(my_time, :time_separator => ':', :include_seconds => true) + # def select_time(datetime = Time.now, options = {}) separator = options[:time_separator] || '' select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '') @@ -178,6 +313,20 @@ module ActionView # Returns a select tag with options for each of the seconds 0 through 59 with the current second selected. # The <tt>second</tt> can also be substituted for a second number. # Override the field name using the <tt>:field_name</tt> option, 'second' by default. + # + # ==== Examples + # my_time = Time.now + 16.minutes + # + # # Generates a select field for seconds that defaults to the seconds for the time in my_time + # select_second(my_time) + # + # # Generates a select field for seconds that defaults to the number given + # select_second(33) + # + # # Generates a select field for seconds that defaults to the seconds for the time in my_time + # # that is named 'interval' rather than 'second' + # select_second(my_time, :field_name => 'interval') + # def select_second(datetime, options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : '' if options[:use_hidden] @@ -198,6 +347,20 @@ module ActionView # Also can return a select tag with options by <tt>minute_step</tt> from 0 through 59 with the 00 minute selected # The <tt>minute</tt> can also be substituted for a minute number. # Override the field name using the <tt>:field_name</tt> option, 'minute' by default. + # + # ==== Examples + # my_time = Time.now + 6.hours + # + # # Generates a select field for minutes that defaults to the minutes for the time in my_time + # select_minute(my_time) + # + # # Generates a select field for minutes that defaults to the number given + # select_minute(14) + # + # # Generates a select field for minutes that defaults to the minutes for the time in my_time + # # that is named 'stride' rather than 'second' + # select_minute(my_time, :field_name => 'stride') + # def select_minute(datetime, options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : '' if options[:use_hidden] @@ -217,6 +380,20 @@ module ActionView # Returns a select tag with options for each of the hours 0 through 23 with the current hour selected. # The <tt>hour</tt> can also be substituted for a hour number. # Override the field name using the <tt>:field_name</tt> option, 'hour' by default. + # + # ==== Examples + # my_time = Time.now + 6.hours + # + # # Generates a select field for minutes that defaults to the minutes for the time in my_time + # select_minute(my_time) + # + # # Generates a select field for minutes that defaults to the number given + # select_minute(14) + # + # # Generates a select field for minutes that defaults to the minutes for the time in my_time + # # that is named 'stride' rather than 'second' + # select_minute(my_time, :field_name => 'stride') + # def select_hour(datetime, options = {}) val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : '' if options[:use_hidden] @@ -236,6 +413,20 @@ module ActionView # Returns a select tag with options for each of the days 1 through 31 with the current day selected. # The <tt>date</tt> can also be substituted for a hour number. # Override the field name using the <tt>:field_name</tt> option, 'day' by default. + # + # ==== Examples + # my_date = Time.today + 2.days + # + # # Generates a select field for days that defaults to the day for the date in my_date + # select_day(my_time) + # + # # Generates a select field for days that defaults to the number given + # select_day(5) + # + # # Generates a select field for days that defaults to the day for the date in my_date + # # that is named 'due' rather than 'day' + # select_day(my_time, :field_name => 'due') + # def select_day(date, options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.day) : '' if options[:use_hidden] @@ -258,17 +449,34 @@ module ActionView # set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names, # set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer to show month names as abbreviations, # set the <tt>:use_short_month</tt> key in +options+ to true. If you want to use your own month names, set the - # <tt>:use_month_names</tt> key in +options+ to an array of 12 month names. + # <tt>:use_month_names</tt> key in +options+ to an array of 12 month names. Override the field name using the + # <tt>:field_name</tt> option, 'month' by default. # - # Examples: + # ==== Examples + # # Generates a select field for months that defaults to the current month that + # # will use keys like "January", "March". + # select_month(Date.today) # - # select_month(Date.today) # Will use keys like "January", "March" - # select_month(Date.today, :use_month_numbers => true) # Will use keys like "1", "3" - # select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March" - # select_month(Date.today, :use_short_month => true) # Will use keys like "Jan", "Mar" - # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # Will use keys like "Januar", "Marts" + # # Generates a select field for months that defaults to the current month that + # # is named "start" rather than "month" + # select_month(Date.today, :field_name => 'start') + # + # # Generates a select field for months that defaults to the current month that + # # will use keys like "1", "3". + # select_month(Date.today, :use_month_numbers => true) + # + # # Generates a select field for months that defaults to the current month that + # # will use keys like "1 - January", "3 - March". + # select_month(Date.today, :add_month_numbers => true) + # + # # Generates a select field for months that defaults to the current month that + # # will use keys like "Jan", "Mar". + # select_month(Date.today, :use_short_month => true) + # + # # Generates a select field for months that defaults to the current month that + # # will use keys like "Januar", "Marts." + # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # - # Override the field name using the <tt>:field_name</tt> option, 'month' by default. def select_month(date, options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.month) : '' if options[:use_hidden] @@ -298,13 +506,25 @@ module ActionView # Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius # can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. Both ascending and descending year # lists are supported by making <tt>:start_year</tt> less than or greater than <tt>:end_year</tt>. The <tt>date</tt> can also be - # substituted for a year given as a number. Example: + # substituted for a year given as a number. Override the field name using the <tt>:field_name</tt> option, 'year' by default. + # + # ==== Examples + # # Generates a select field for years that defaults to the current year that + # # has ascending year values + # select_year(Date.today, :start_year => 1992, :end_year => 2007) + # + # # Generates a select field for years that defaults to the current year that + # # is named 'birth' rather than 'year' + # select_year(Date.today, :field_name => 'birth') + # + # # Generates a select field for years that defaults to the current year that + # # has descending year values + # select_year(Date.today, :start_year => 2005, :end_year => 1900) # - # select_year(Date.today, :start_year => 1992, :end_year => 2007) # ascending year values - # select_year(Date.today, :start_year => 2005, :end_year => 1900) # descending year values + # # Generates a select field for years that defaults to the year 2006 that + # # has ascending year values # select_year(2006, :start_year => 2000, :end_year => 2010) # - # Override the field name using the <tt>:field_name</tt> option, 'year' by default. def select_year(date, options = {}) val = date ? (date.kind_of?(Fixnum) ? date : date.year) : '' if options[:use_hidden] diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index cf8fb74f59..bf82fa234a 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -3,33 +3,36 @@ require 'action_view/helpers/tag_helper' module ActionView module Helpers - # Provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like - # FormHelper does. With the FormTagHelper, you provide the names and values yourself. + # Provides a number of methods for creating form tags that doesn't rely on an ActiveRecord object assigned to the template like + # FormHelper does. Instead, you provide the names and values manually. # - # NOTE: The html options disabled, readonly, and multiple can all be treated as booleans. So specifying <tt>:disabled => true</tt> - # will give <tt>disabled="disabled"</tt>. + # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying + # <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>. module FormTagHelper # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like # ActionController::Base#url_for. The method for the form defaults to POST. # - # Examples: - # * <tt>form_tag('/posts') => <form action="/posts" method="post"></tt> - # * <tt>form_tag('/posts/1', :method => :put) => <form action="/posts/1" method="put"></tt> - # * <tt>form_tag('/upload', :multipart => true) => <form action="/upload" method="post" enctype="multipart/form-data"></tt> - # - # ERb example: - # <% form_tag '/posts' do -%> - # <div><%= submit_tag 'Save' %></div> - # <% end -%> - # - # Will output: - # <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form> - # - # Options: + # ==== Options # * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data". # * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post". # If "put", "delete", or another verb is used, a hidden input with name _method # is added to simulate the verb over post. + # * A list of parameters to feed to the URL the form will be posted to. + # + # ==== Examples + # form_tag('/posts') + # # => <form action="/posts" method="post"> + # + # form_tag('/posts/1', :method => :put) + # # => <form action="/posts/1" method="put"> + # + # form_tag('/upload', :multipart => true) + # # => <form action="/upload" method="post" enctype="multipart/form-data"> + # + # <% form_tag '/posts' do -%> + # <div><%= submit_tag 'Save' %></div> + # <% end -%> + # # => <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form> def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block) html_options = html_options_for_form(url_for_options, options, *parameters_for_url) if block_given? @@ -39,45 +42,101 @@ module ActionView end end - # Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple # choice selection box. # # Helpers::FormOptions can be used to create common select boxes such as countries, time zones, or - # associated records. + # associated records. <tt>option_tags</tt> is a string containing the option tags for the select box. + # + # ==== Options + # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices. + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * Any other key creates standard HTML attributes for the tag. # - # <tt>option_tags</tt> is a string containing the option tags for the select box: - # # Outputs <select id="people" name="people"><option>David</option></select> + # ==== Examples # select_tag "people", "<option>David</option>" + # # => <select id="people" name="people"><option>David</option></select> # - # Options: - # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices. + # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>" + # # => <select id="count" name="count"><option>1</option><option>2</option> + # # <option>3</option><option>4</option></select> + # + # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true + # # => <select id="colors" multiple="multiple" name="colors"><option>Red</option> + # # <option>Green</option><option>Blue</option></select> + # + # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>" + # # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option> + # # <option>Out</option></select> + # + # select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input' + # # => <select class="form_input" id="access" multiple="multiple" name="access"><option>Read</option> + # # <option>Write</option></select> + # + # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true + # # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option> + # # <option>Paris</option><option>Rome</option></select> def select_tag(name, option_tags = nil, options = {}) content_tag :select, option_tags, { "name" => name, "id" => name }.update(options.stringify_keys) end - # Creates a standard text field. + # Creates a standard text field; use these text fields to input smaller chunks of text like a username + # or a search query. # - # Options: + # ==== Options # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. # * <tt>:size</tt> - The number of visible characters that will fit in the input. # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter. + # * Any other key creates standard HTML attributes for the tag. # - # A hash of standard HTML options for the tag. + # ==== Examples + # text_field_tag 'name' + # # => <input id="name" name="name" type="text" /> + # + # text_field_tag 'query', 'Enter your search query here' + # # => <input id="query" name="query" type="text" value="Enter your search query here" /> + # + # text_field_tag 'request', nil, :class => 'special_input' + # # => <input class="special_input" id="request" name="request" type="text" /> + # + # text_field_tag 'address', '', :size => 75 + # # => <input id="address" name="address" size="75" type="text" value="" /> + # + # text_field_tag 'zip', nil, :maxlength => 5 + # # => <input id="zip" maxlength="5" name="zip" type="text" /> + # + # text_field_tag 'payment_amount', '$0.00', :disabled => true + # # => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" /> + # + # text_field_tag 'ip', '0.0.0.0', :maxlength => 15, :size => 20, :class => "ip-input" + # # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" /> def text_field_tag(name, value = nil, options = {}) tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys) end - # Creates a hidden field. + # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or + # data that should be hidden from the user. + # + # ==== Options + # * Creates standard HTML attributes for the tag. + # + # ==== Examples + # hidden_field_tag 'tags_list' + # # => <input id="tags_list" name="tags_list" type="hidden" /> # - # Takes the same options as text_field_tag + # hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@' + # # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" /> + # + # hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')" + # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')" + # # type="hidden" value="" /> def hidden_field_tag(name, value = nil, options = {}) text_field_tag(name, value, options.stringify_keys.update("type" => "hidden")) end - # Creates a file upload field. + # Creates a file upload field. If you are using file uploads then you will also need + # to set the multipart option for the form tag: # - # If you are using file uploads then you will also need to set the multipart option for the form: # <%= form_tag { :action => "post" }, { :multipart => true } %> # <label for="file">File to Upload</label> <%= file_field_tag "file" %> # <%= submit_tag %> @@ -85,23 +144,93 @@ module ActionView # # The specified URL will then be passed a File object containing the selected file, or if the field # was left blank, a StringIO object. + # + # ==== Options + # * Creates standard HTML attributes for the tag. + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # + # ==== Examples + # file_field_tag 'attachment' + # # => <input id="attachment" name="attachment" type="file" /> + # + # file_field_tag 'avatar', :class => 'profile-input' + # # => <input class="profile-input" id="avatar" name="avatar" type="file" /> + # + # file_field_tag 'picture', :disabled => true + # # => <input disabled="disabled" id="picture" name="picture" type="file" /> + # + # file_field_tag 'resume', :value => '~/resume.doc' + # # => <input id="resume" name="resume" type="file" value="~/resume.doc" /> + # + # file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg' + # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" /> + # + # file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html' + # # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" /> def file_field_tag(name, options = {}) text_field_tag(name, nil, options.update("type" => "file")) end - # Creates a password field. + # Creates a password field, a masked text field that will hide the users input behind a mask character. # - # Takes the same options as text_field_tag + # ==== Options + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * <tt>:size</tt> - The number of visible characters that will fit in the input. + # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter. + # * Any other key creates standard HTML attributes for the tag. + # + # ==== Examples + # password_field_tag 'pass' + # # => <input id="pass" name="pass" type="password" /> + # + # password_field_tag 'secret', 'Your secret here' + # # => <input id="secret" name="secret" type="password" value="Your secret here" /> + # + # password_field_tag 'masked', nil, :class => 'masked_input_field' + # # => <input class="masked_input_field" id="masked" name="masked" type="password" /> + # + # password_field_tag 'token', '', :size => 15 + # # => <input id="token" name="token" size="15" type="password" value="" /> + # + # password_field_tag 'key', nil, :maxlength => 16 + # # => <input id="key" maxlength="16" name="key" type="password" /> + # + # password_field_tag 'confirm_pass', nil, :disabled => true + # # => <input disabled="disabled" id="confirm_pass" name="confirm_pass" type="password" /> + # + # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin-input" + # # => <input class="pin-input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" /> def password_field_tag(name = "password", value = nil, options = {}) text_field_tag(name, value, options.update("type" => "password")) end - # Creates a text input area. + # Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions. + # + # ==== Options + # * <tt>:size</tt> - A string specifying the dimensions of the textarea using dimensions (e.g., "25x10"). + # * <tt>:rows</tt> - Specify the number of rows in the textarea + # * <tt>:cols</tt> - Specify the number of columns in the textarea + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * Any other key creates standard HTML attributes for the tag. + # + # ==== Examples + # text_area_tag 'post' + # # => <textarea id="post" name="post"></textarea> + # + # text_area_tag 'bio', @user.bio + # # => <textarea id="bio" name="bio">This is my biography.</textarea> # - # Options: - # * <tt>:size</tt> - A string specifying the dimensions of the textarea. - # # Outputs <textarea name="body" id="body" cols="25" rows="10"></textarea> - # <%= text_area_tag "body", nil, :size => "25x10" %> + # text_area_tag 'body', nil, :rows => 10, :cols => 25 + # # => <textarea cols="25" id="body" name="body" rows="10"></textarea> + # + # text_area_tag 'body', nil, :size => "25x10" + # # => <textarea name="body" id="body" cols="25" rows="10"></textarea> + # + # text_area_tag 'description', "Description goes here.", :disabled => true + # # => <textarea disabled="disabled" id="description" name="description">Description goes here.</textarea> + # + # text_area_tag 'comment', nil, :class => 'comment_input' + # # => <textarea class="comment_input" id="comment" name="comment"></textarea> def text_area_tag(name, content = nil, options = {}) options.stringify_keys! @@ -112,14 +241,52 @@ module ActionView content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys) end - # Creates a check box. + # Creates a check box form input tag. + # + # ==== Options + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * Any other key creates standard HTML options for the tag. + # + # ==== Examples + # check_box_tag 'accept' + # # => <input id="accept" name="accept" type="checkbox" value="1" /> + # + # check_box_tag 'rock', 'rock music' + # # => <input id="rock" name="rock" type="checkbox" value="rock music" /> + # + # check_box_tag 'receive_email', 'yes', true + # # => <input checked="checked" id="receive_email" name="receive_email" type="checkbox" value="yes" /> + # + # check_box_tag 'tos', 'yes', false, :class => 'accept_tos' + # # => <input class="accept_tos" id="tos" name="tos" type="checkbox" value="yes" /> + # + # check_box_tag 'eula', 'accepted', false, :disabled => true + # # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" /> def check_box_tag(name, value = "1", checked = false, options = {}) html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys) html_options["checked"] = "checked" if checked tag :input, html_options end - # Creates a radio button. + # Creates a radio button; use groups of radio buttons named the same to allow users to + # select from a group of options. + # + # ==== Options + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * Any other key creates standard HTML options for the tag. + # + # ==== Examples + # radio_button_tag 'gender', 'male' + # # => <input id="gender_male" name="gender" type="radio" value="male" /> + # + # radio_button_tag 'receive_updates', 'no', true + # # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" /> + # + # radio_button_tag 'time_slot', "3:00 p.m.", false, :disabled => true + # # => <input disabled="disabled" id="time_slot_300_pm" name="time_slot" type="radio" value="3:00 p.m." /> + # + # radio_button_tag 'color', "green", true, :class => "color_input" + # # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" /> def radio_button_tag(name, value, checked = false, options = {}) pretty_tag_value = value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "").downcase pretty_name = name.gsub(/\[/, "_").gsub(/\]/, "") @@ -128,14 +295,33 @@ module ActionView tag :input, html_options end - # Creates a submit button with the text <tt>value</tt> as the caption. If options contains a pair with the key of <tt>:disable_with</tt>, - # then the value will be used to rename a disabled version of the submit button. - # - # Options: - # * <tt>:disable_with</tt> - When specified the button will be disabled when clicked and the <tt>value</tt> will be replaced with the - # the string provided. - # # Outputs <input name="commit" onclick="this.disabled=true;this.value='Saving...';this.form.submit();" type="submit" value="Send" /> - # <%= submit_tag 'Send', :disable_with => 'Saving...' %> + # Creates a submit button with the text <tt>value</tt> as the caption. + # + # ==== Options + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version + # of the submit button when the form is submitted. + # * Any other key creates standard HTML options for the tag. + # + # ==== Examples + # submit_tag + # # => <input name="commit" type="submit" value="Save changes" /> + # + # submit_tag "Edit this article" + # # => <input name="commit" type="submit" value="Edit this article" /> + # + # submit_tag "Save edits", :disabled => true + # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" /> + # + # submit_tag "Complete sale", :disable_with => "Please wait..." + # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();" + # # type="submit" value="Complete sale" /> + # + # submit_tag nil, :class => "form_submit" + # # => <input class="form_submit" name="commit" type="submit" /> + # + # submit_tag "Edit", :disable_width => "Editing...", :class => 'edit-button' + # # => <input class="edit-button" disable_width="Editing..." name="commit" type="submit" value="Edit" /> def submit_tag(value = "Save changes", options = {}) options.stringify_keys! @@ -157,6 +343,23 @@ module ActionView # Displays an image which when clicked will submit the form. # # <tt>source</tt> is passed to AssetTagHelper#image_path + # + # ==== Options + # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * Any other key creates standard HTML options for the tag. + # + # ==== Examples + # image_submit_tag("login.png") + # # => <input src="/images/login.png" type="image" /> + # + # image_submit_tag("purchase.png"), :disabled => true + # # => <input disabled="disabled" src="/images/purchase.png" type="image" /> + # + # image_submit_tag("search.png"), :class => 'search-button' + # # => <input class="search-button" src="/images/search.png" type="image" /> + # + # image_submit_tag("agree.png"), :disabled => true, :class => "agree-disagree-button" + # # => <input class="agree-disagree-button" disabled="disabled" src="/images/agree.png" type="image" /> def image_submit_tag(source, options = {}) tag :input, { "type" => "image", "src" => image_path(source) }.update(options.stringify_keys) end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 90ff164a5d..e2db853f93 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -4,19 +4,25 @@ module ActionView # Methods are provided for phone numbers, currency, percentage, # precision, positional notation, and file size. module NumberHelper - # Formats a +number+ into a US phone number. You can customize the format + # Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format # in the +options+ hash. + # + # ==== Options # * <tt>:area_code</tt> - Adds parentheses around the area code. - # * <tt>:delimiter</tt> - Specifies the delimiter to use, defaults to "-". + # * <tt>:delimiter</tt> - Specifies the delimiter to use (defaults to "-"). # * <tt>:extension</tt> - Specifies an extension to add to the end of the - # generated number + # generated number. # * <tt>:country_code</tt> - Sets the country code for the phone number. # - # number_to_phone(1235551234) => 123-555-1234 - # number_to_phone(1235551234, :area_code => true) => (123) 555-1234 - # number_to_phone(1235551234, :delimiter => " ") => 123 555 1234 - # number_to_phone(1235551234, :area_code => true, :extension => 555) => (123) 555-1234 x 555 - # number_to_phone(1235551234, :country_code => 1) + # ==== Examples + # number_to_phone(1235551234) # => 123-555-1234 + # number_to_phone(1235551234, :area_code => true) # => (123) 555-1234 + # number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234 + # number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555 + # number_to_phone(1235551234, :country_code => 1) # => +1-123-555-1234 + # + # number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimeter => ".") + # => +1.123.555.1234 x 1343 def number_to_phone(number, options = {}) number = number.to_s.strip unless number.nil? options = options.stringify_keys @@ -40,18 +46,22 @@ module ActionView end end - # Formats a +number+ into a currency string. You can customize the format + # Formats a +number+ into a currency string (e.g., $13.65). You can customize the format # in the +options+ hash. - # * <tt>:precision</tt> - Sets the level of precision, defaults to 2 - # * <tt>:unit</tt> - Sets the denomination of the currency, defaults to "$" - # * <tt>:separator</tt> - Sets the separator between the units, defaults to "." - # * <tt>:delimiter</tt> - Sets the thousands delimiter, defaults to "," # - # number_to_currency(1234567890.50) => $1,234,567,890.50 - # number_to_currency(1234567890.506) => $1,234,567,890.51 - # number_to_currency(1234567890.506, :precision => 3) => $1,234,567,890.506 + # ==== Options + # * <tt>:precision</tt> - Sets the level of precision (defaults to 2). + # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$"). + # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ","). + # + # ==== Examples + # number_to_currency(1234567890.50) # => $1,234,567,890.50 + # number_to_currency(1234567890.506) # => $1,234,567,890.51 + # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506 + # # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "") - # => £1234567890,50 + # # => £1234567890,50 def number_to_currency(number, options = {}) options = options.stringify_keys precision = options["precision"] || 2 @@ -67,14 +77,19 @@ module ActionView end end - # Formats a +number+ as a percentage string. You can customize the + # Formats a +number+ as a percentage string (e.g., 65%). You can customize the # format in the +options+ hash. - # * <tt>:precision</tt> - Sets the level of precision, defaults to 3 - # * <tt>:separator</tt> - Sets the separator between the units, defaults to "." # - # number_to_percentage(100) => 100.000% - # number_to_percentage(100, {:precision => 0}) => 100% - # number_to_percentage(302.0574, {:precision => 2}) => 302.06% + # ==== Options + # * <tt>:precision</tt> - Sets the level of precision (defaults to 3). + # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # + # ==== Examples + # number_to_percentage(100) # => 100.000% + # number_to_percentage(100, :precision => 0) # => 100% + # + # number_to_percentage(302.24398923423, :precision => 5) + # # => 302.24399% def number_to_percentage(number, options = {}) options = options.stringify_keys precision = options["precision"] || 3 @@ -93,14 +108,20 @@ module ActionView end end - # Formats a +number+ with grouped thousands using +delimiter+. You + # Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You # can customize the format using optional <em>delimiter</em> and <em>separator</em> parameters. - # * <tt>delimiter</tt> - Sets the thousands delimiter, defaults to "," - # * <tt>separator</tt> - Sets the separator between the units, defaults to "." # - # number_with_delimiter(12345678) => 12,345,678 - # number_with_delimiter(12345678.05) => 12,345,678.05 - # number_with_delimiter(12345678, ".") => 12.345.678 + # ==== Options + # * <tt>delimiter</tt> - Sets the thousands delimiter (defaults to ","). + # * <tt>separator</tt> - Sets the separator between the units (defaults to "."). + # + # ==== Examples + # number_with_delimiter(12345678) # => 12,345,678 + # number_with_delimiter(12345678.05) # => 12,345,678.05 + # number_with_delimiter(12345678, ".") # => 12.345.678 + # + # number_with_delimiter(98765432.98, " ", ",") + # # => 98 765 432,98 def number_with_delimiter(number, delimiter=",", separator=".") begin parts = number.to_s.split('.') @@ -111,29 +132,35 @@ module ActionView end end - # Formats a +number+ with the specified level of +precision+. The default + # Formats a +number+ with the specified level of +precision+ (e.g., 112.32 has a precision of 2). The default # level of precision is 3. # - # number_with_precision(111.2345) => 111.235 - # number_with_precision(111.2345, 2) => 111.24 + # ==== Examples + # number_with_precision(111.2345) # => 111.235 + # number_with_precision(111.2345, 2) # => 111.24 + # number_with_precision(13, 5) # => 13.00000 + # number_with_precision(389.32314, 0) # => 389 def number_with_precision(number, precision=3) "%01.#{precision}f" % number rescue number end - # Formats the bytes in +size+ into a more understandable representation. - # Useful for reporting file sizes to users. This method returns nil if + # 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 # +size+ cannot be converted into a number. You can change the default - # precision of 1 in +precision+. + # precision of 1 using the precision parameter +precision+. # - # number_to_human_size(123) => 123 Bytes - # number_to_human_size(1234) => 1.2 KB - # number_to_human_size(12345) => 12.1 KB - # number_to_human_size(1234567) => 1.2 MB - # number_to_human_size(1234567890) => 1.1 GB - # number_to_human_size(1234567890123) => 1.1 TB - # number_to_human_size(1234567, 2) => 1.18 MB + # ==== Examples + # number_to_human_size(123) # => 123 Bytes + # number_to_human_size(1234) # => 1.2 KB + # number_to_human_size(12345) # => 12.1 KB + # number_to_human_size(1234567) # => 1.2 MB + # number_to_human_size(1234567890) # => 1.1 GB + # number_to_human_size(1234567890123) # => 1.1 TB + # number_to_human_size(1234567, 2) # => 1.18 MB + # number_to_human_size(483989, 0) # => 4 MB def number_to_human_size(size, precision=1) size = Kernel.Float(size) case diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 7c6903220a..8d3f6be04c 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -3,7 +3,7 @@ require 'erb' module ActionView module Helpers #:nodoc: - # Use these methods to generate HTML tags programmatically when you can't use + # Provides methods to generate HTML tags programmatically when you can't use # a Builder. By default, they output XHTML compliant tags. module TagHelper include ERB::Util @@ -11,25 +11,40 @@ module ActionView # Returns an empty HTML tag of type +name+ which by default is XHTML # compliant. Setting +open+ to true will create an open tag compatible # with HTML 4.0 and below. Add HTML attributes by passing an attributes - # hash to +options+. For attributes with no value like (disabled and - # readonly), give it a value of true in the +options+ hash. You can use + # hash to +options+. + # + # ==== Options + # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and + # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use # symbols or strings for the attribute names. # + # ==== Examples # tag("br") - # # => <br /> + # # => <br /> + # # tag("br", nil, true) - # # => <br> + # # => <br> + # # tag("input", { :type => 'text', :disabled => true }) - # # => <input type="text" disabled="disabled" /> + # # => <input type="text" disabled="disabled" /> + # + # tag("img", { :src => "open.png" }) + # # => <img src="open.png" /> def tag(name, options = nil, open = false) "<#{name}#{tag_options(options) if options}" + (open ? ">" : " />") end # Returns an HTML block tag of type +name+ surrounding the +content+. Add - # HTML attributes by passing an attributes hash to +options+. For attributes - # with no value like (disabled and readonly), give it a value of true in - # the +options+ hash. You can use symbols or strings for the attribute names. + # HTML attributes by passing an attributes hash to +options+. + # Instead of passing the content as an argument, you can also use a block + # in which case, you pass your +options+ as the second parameter. # + # ==== Options + # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and + # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use + # symbols or strings for the attribute names. + # + # ==== Examples # content_tag(:p, "Hello world!") # # => <p>Hello world!</p> # content_tag(:div, content_tag(:p, "Hello world!"), :class => "strong") @@ -37,9 +52,6 @@ module ActionView # content_tag("select", options, :multiple => true) # # => <select multiple="multiple">...options...</select> # - # Instead of passing the content as an argument, you can also use a block - # in which case, you pass your +options+ as the second parameter. - # # <% content_tag :div, :class => "strong" do -%> # Hello world! # <% end -%> @@ -61,16 +73,24 @@ module ActionView # otherwise be recognized as markup. CDATA sections begin with the string # <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>. # + # ==== Examples # cdata_section("<hello world>") - # # => <![CDATA[<hello world>]]> + # # => <![CDATA[<hello world>]]> + # + # cdata_section(File.read("hello_world.txt")) + # # => <![CDATA[<hello from a text file]]> def cdata_section(content) "<![CDATA[#{content}]]>" end - # Returns the escaped +html+ without affecting existing escaped entities. + # Returns an escaped version of +html+ without affecting existing escaped entities. # + # ==== Examples # escape_once("1 > 2 & 3") - # # => "1 < 2 & 3" + # # => "1 < 2 & 3" + # + # escape_once("<< Accept & Checkout") + # # => "<< Accept & Checkout" def escape_once(html) fix_double_escape(html_escape(html.to_s)) end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index d986233796..8db8ce7009 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -3,35 +3,48 @@ require 'html/document' module ActionView module Helpers #:nodoc: - # The TextHelper Module provides a set of methods for filtering, formatting - # and transforming strings that can reduce the amount of inline Ruby code in + # The TextHelper module provides a set of methods for filtering, formatting + # and transforming strings, which can reduce the amount of inline Ruby code in # your views. These helper methods extend ActionView making them callable - # within your template files as shown in the following example which truncates - # the title of each post to 10 characters. - # - # <% @posts.each do |post| %> - # # post == 'This is my title' - # Title: <%= truncate(post.title, 10) %> - # <% end %> - # => Title: This is my... + # within your template files. module TextHelper # The preferred method of outputting text in your views is to use the # <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods # do not operate as expected in an eRuby code block. If you absolutely must - # output text within a code block, you can use the concat method. + # output text within a non-output code block (i.e., <% %>), you can use the concat method. # - # <% concat "hello", binding %> - # is equivalent to using: - # <%= "hello" %> + # ==== Examples + # <% + # concat "hello", binding + # # is the equivalent of <%= "hello" %> + # + # if (logged_in == true): + # concat "Logged in!", binding + # else + # concat link_to('login', :action => login), binding + # end + # # will either display "Logged in!" or a login link + # %> def concat(string, binding) eval(ActionView::Base.erb_variable, binding) << string end # If +text+ is longer than +length+, +text+ will be truncated to the length of - # +length+ and the last three characters will be replaced with the +truncate_string+. + # +length+ (defaults to 30) and the last three characters will be replaced with the +truncate_string+ + # (defaults to "..."). # + # ==== Examples # truncate("Once upon a time in a world far far away", 14) - # => Once upon a... + # # => Once upon a... + # + # truncate("Once upon a time in a world far far away") + # # => Once upon a time in a world f... + # + # truncate("And they found that many people were sleeping better.", 25, "(clipped)") + # # => And they found that many (clipped) + # + # truncate("And they found that many people were sleeping better.", 15, "... (continued)") + # # => And they found... (continued) def truncate(text, length = 30, truncate_string = "...") if text.nil? then return end l = length - truncate_string.chars.length @@ -40,13 +53,21 @@ module ActionView # Highlights one or more +phrases+ everywhere in +text+ by inserting it into # a +highlighter+ string. The highlighter can be specialized by passing +highlighter+ - # as a single-quoted string with \1 where the phrase is to be inserted. + # as a single-quoted string with \1 where the phrase is to be inserted (defaults to + # '<strong class="highlight">\1</strong>') # + # ==== Examples # highlight('You searched for: rails', 'rails') # # => You searched for: <strong class="highlight">rails</strong> # + # highlight('You searched for: ruby, rails, dhh', 'actionpack') + # # => You searched for: ruby, rails, dhh + # # highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>') # # => You searched <em>for</em>: <em>rails</em> + # + # highlight('You searched for: rails', 'rails', "<a href='search?q=\1'>\1</a>") + # # => You searched for: <a href='search?q=rails>rails</a> def highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>') if text.blank? || phrases.blank? text @@ -57,16 +78,26 @@ module ActionView end # Extracts an excerpt from +text+ that matches the first instance of +phrase+. - # The +radius+ expands the excerpt on each side of +phrase+ by the number of characters - # defined in +radius+. If the excerpt radius overflows the beginning or end of the +text+, + # The +radius+ expands the excerpt on each side of the first occurance of +phrase+ by the number of characters + # defined in +radius+ (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+, # then the +excerpt_string+ will be prepended/appended accordingly. If the +phrase+ # isn't found, nil is returned. # + # ==== Examples # excerpt('This is an example', 'an', 5) - # => "...s is an examp..." + # # => "...s is an examp..." # # excerpt('This is an example', 'is', 5) - # => "This is an..." + # # => "This is an..." + # + # excerpt('This is an example', 'is') + # # => "This is an example" + # + # excerpt('This next thing is an example', 'ex', 2) + # # => "...next t..." + # + # excerpt('This is also an example', 'an', 8, '<chop> ') + # # => "<chop> is also an example" def excerpt(text, phrase, radius = 100, excerpt_string = "...") if text.nil? || phrase.nil? then return end phrase = Regexp.escape(phrase) @@ -89,9 +120,18 @@ module ActionView # is loaded, it will use the Inflector to determine the plural form, otherwise # it will just add an 's' to the +singular+ word. # - # pluralize(1, 'person') => 1 person - # pluralize(2, 'person') => 2 people - # pluralize(3, 'person', 'users') => 3 users + # ==== Examples + # pluralize(1, 'person') + # # => 1 person + # + # pluralize(2, 'person') + # # => 2 people + # + # pluralize(3, 'person', 'users') + # # => 3 users + # + # pluralize(0, 'person') + # # => 0 people def pluralize(count, singular, plural = nil) "#{count || 0} " + if count == 1 || count == '1' singular @@ -105,10 +145,21 @@ module ActionView end # Wraps the +text+ into lines no longer than +line_width+ width. This method - # breaks on the first whitespace character that does not exceed +line_width+. + # breaks on the first whitespace character that does not exceed +line_width+ + # (which is 80 by default). # + # ==== Examples # word_wrap('Once upon a time', 4) - # => Once\nupon\na\ntime + # # => Once\nupon\na\ntime + # + # word_wrap('Once upon a time', 8) + # # => Once upon\na time + # + # word_wrap('Once upon a time') + # # => Once upon a time + # + # word_wrap('Once upon a time', 1) + # # => Once\nupon\na\ntime def word_wrap(text, line_width = 80) text.gsub(/\n/, "\n\n").gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip end @@ -116,9 +167,24 @@ module ActionView begin require_library_or_gem "redcloth" unless Object.const_defined?(:RedCloth) - # Returns the text with all the Textile codes turned into HTML tags. + # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags. + # + # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile]. # <i>This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/] # is available</i>. + # + # ==== Examples + # textilize("*This is Textile!* Rejoice!") + # # => "<p><strong>This is Textile!</strong> Rejoice!</p>" + # + # textilize("I _love_ ROR(Ruby on Rails)!") + # # => "<p>I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!</p>" + # + # textilize("h2. Textile makes markup -easy- simple!") + # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>" + # + # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.) + # # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>" def textilize(text) if text.blank? "" @@ -131,8 +197,23 @@ module ActionView # Returns the text with all the Textile codes turned into HTML tags, # but without the bounding <p> tag that RedCloth adds. + # + # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile]. # <i>This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/] # is available</i>. + # + # ==== Examples + # textilize_without_paragraph("*This is Textile!* Rejoice!") + # # => "<strong>This is Textile!</strong> Rejoice!" + # + # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!") + # # => "I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!" + # + # textilize_without_paragraph("h2. Textile makes markup -easy- simple!") + # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>" + # + # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.) + # # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>." def textilize_without_paragraph(text) textiled = textilize(text) if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end @@ -149,6 +230,20 @@ module ActionView # Returns the text with all the Markdown codes turned into HTML tags. # <i>This method is only available if BlueCloth[http://www.deveiate.org/projects/BlueCloth] # is available</i>. + # + # ==== Examples + # markdown("We are using __Markdown__ now!") + # # => "<p>We are using <strong>Markdown</strong> now!</p>" + # + # markdown("We like to _write_ `code`, not just _read_ it!") + # # => "<p>We like to <em>write</em> <code>code</code>, not just <em>read</em> it!</p>" + # + # markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.") + # # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a> + # # has more information.</p>" + # + # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")') + # # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>' def markdown(text) text.blank? ? "" : BlueCloth.new(text).to_html end @@ -161,6 +256,20 @@ module ActionView # paragraph and wrapped in <tt><p></tt> tags. One newline (<tt>\n</tt>) is # considered as a linebreak and a <tt><br /></tt> tag is appended. This # method does not remove the newlines from the +text+. + # + # ==== Examples + # my_text = """Here is some basic text... + # ...with a line break.""" + # + # simple_format(my_text) + # # => "<p>Here is some basic text...<br />...with a line break.</p>" + # + # more_text = """We want to put a paragraph... + # + # ...right there.""" + # + # simple_format(more_text) + # # => "<p>We want to put a paragraph...</p><p>...right there.</p>" def simple_format(text) content_tag 'p', text.to_s. gsub(/\r\n?/, "\n"). # \r\n and \r -> \n @@ -168,21 +277,31 @@ module ActionView gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br end - # Turns all urls and email addresses into clickable links. The +link+ parameter - # will limit what should be linked. You can add html attributes to the links using + # Turns all URLs and e-mail addresses into clickable links. The +link+ parameter + # will limit what should be linked. You can add HTML attributes to the links using # +href_options+. Options for +link+ are <tt>:all</tt> (default), - # <tt>:email_addresses</tt>, and <tt>:urls</tt>. + # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and + # e-mail address is yielded and the result is used as the link text. + # + # ==== Examples + # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com") + # # => "Go to <a href="http://www.rubyonrails.org">http://www.rubyonrails.org</a> and + # # say hello to <a href="mailto:david@loudthinking.com">david@loudthinking.com</a>" # - # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com") => - # Go to <a href="http://www.rubyonrails.org">http://www.rubyonrails.org</a> and - # say hello to <a href="mailto:david@loudthinking.com">david@loudthinking.com</a> + # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :urls) + # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a> + # # or e-mail david@loudthinking.com" # - # If a block is given, each url and email address is yielded and the - # result is used as the link text. + # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :email_addresses) + # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>" # - # auto_link(post.body, :all, :target => '_blank') do |text| + # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." + # auto_link(post_body, :all, :target => '_blank') do |text| # truncate(text, 15) # end + # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>. + # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>." + # def auto_link(text, link = :all, href_options = {}, &block) return '' if text.blank? case link @@ -192,10 +311,17 @@ module ActionView end end - # Strips link tags from +text+ leaving just the link label. + # Strips all link tags from +text+ leaving just the link text. # + # ==== Examples # strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>') - # => Ruby on Rails + # # => Ruby on Rails + # + # strip_links('Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.') + # # => Please e-mail me at me@email.com. + # + # strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.') + # # => Blog: Visit def strip_links(text) text.gsub(/<a\b.*?>(.*?)<\/a>/mi, '\1') end @@ -204,15 +330,23 @@ module ActionView VERBOTEN_ATTRS = /^on/i unless defined?(VERBOTEN_ATTRS) # Sanitizes the +html+ by converting <form> and <script> tags into regular - # text, and removing all "onxxx" attributes (so that arbitrary Javascript - # cannot be executed). It also removes href= and src= attributes that start with + # text, and removing all "on*" (e.g., onClick) attributes so that arbitrary Javascript + # cannot be executed. It also removes <tt>href</tt> and <tt>src</tt> attributes that start with # "javascript:". You can modify what gets sanitized by defining VERBOTEN_TAGS # and VERBOTEN_ATTRS before this Module is loaded. # + # ==== Examples # sanitize('<script> do_nasty_stuff() </script>') - # => <script> do_nasty_stuff() </script> + # # => <script> do_nasty_stuff() </script> + # # sanitize('<a href="javascript: sucker();">Click here for $100</a>') - # => <a>Click here for $100</a> + # # => <a>Click here for $100</a> + # + # sanitize('<a href="#" onClick="kill_all_humans();">Click here!!!</a>') + # # => <a href="#">Click here!!!</a> + # + # sanitize('<img src="javascript:suckers_run_this();" />') + # # => <img /> def sanitize(html) # only do this if absolutely necessary if html.index("<") @@ -248,6 +382,16 @@ module ActionView # Strips all HTML tags from the +html+, including comments. This uses the # html-scanner tokenizer and so its HTML parsing ability is limited by # that of html-scanner. + # + # ==== Examples + # strip_tags("Strip <i>these</i> tags!") + # # => Strip these tags! + # + # strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...") + # # => Bold no more! See more here... + # + # strip_tags("<div id='top-bar'>Welcome to my website!</div>") + # # => Welcome to my website! def strip_tags(html) return html if html.blank? if html.index("<") @@ -269,25 +413,34 @@ module ActionView # Creates a Cycle object whose _to_s_ method cycles through elements of an # array every time it is called. This can be used for example, to alternate - # classes for table rows: + # classes for table rows. You can use named cycles to allow nesting in loops. + # Passing a Hash as the last parameter with a <tt>:name</tt> key will create a + # named cycle. You can manually reset a cycle by calling reset_cycle and passing the + # name of the cycle. # + # ==== Examples + # # Alternate CSS classes for even and odd numbers... + # @items = [1,2,3,4] + # <table> # <% @items.each do |item| %> # <tr class="<%= cycle("even", "odd") -%>"> # <td>item</td> # </tr> # <% end %> + # </table> # - # You can use named cycles to allow nesting in loops. Passing a Hash as - # the last parameter with a <tt>:name</tt> key will create a named cycle. - # You can manually reset a cycle by calling reset_cycle and passing the - # name of the cycle. # + # # Cycle CSS classes for rows, and text colors for values within each row + # @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'}, + # {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'}, + # {:first => 'June', :middle => 'Dae', :last => 'Jones'}] # <% @items.each do |item| %> # <tr class="<%= cycle("even", "odd", :name => "row_class") # <td> # <% item.values.each do |value| %> + # <!-- Create a named cycle "colors" --> # <span style="color:<%= cycle("red", "green", "blue", :name => "colors") -%>"> - # value + # <%= value %> # </span> # <% end %> # <% reset_cycle("colors") %> @@ -312,6 +465,23 @@ module ActionView # Resets a cycle so that it starts from the first element the next time # it is called. Pass in +name+ to reset a named cycle. + # + # ==== Example + # # Alternate CSS classes for even and odd numbers... + # @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]] + # <table> + # <% @items.each do |item| %> + # <tr class="<%= cycle("even", "odd") -%>"> + # <% item.each do |value| %> + # <span style="color:<%= cycle("#333", "#666", "#999", :name => "colors") -%>"> + # <%= value %> + # </span> + # <% end %> + # + # <% reset_cycle("colors") %> + # </tr> + # <% end %> + # </table> def reset_cycle(name = "default") cycle = get_cycle(name) cycle.reset unless cycle.nil? |