diff options
Diffstat (limited to 'actionpack/lib/action_view/helpers')
11 files changed, 123 insertions, 164 deletions
diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb index c339e10701..8b56d241ae 100644 --- a/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -246,7 +246,7 @@ module ActionView alias_method :tag_without_error_wrapping, :tag def tag(name, options) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name)) else tag_without_error_wrapping(name, options) @@ -255,7 +255,7 @@ module ActionView alias_method :content_tag_without_error_wrapping, :content_tag def content_tag(name, value, options) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name)) else content_tag_without_error_wrapping(name, value, options) @@ -264,7 +264,7 @@ module ActionView alias_method :to_date_select_tag_without_error_wrapping, :to_date_select_tag def to_date_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_date_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_date_select_tag_without_error_wrapping(options, html_options) @@ -273,7 +273,7 @@ module ActionView alias_method :to_datetime_select_tag_without_error_wrapping, :to_datetime_select_tag def to_datetime_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_datetime_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_datetime_select_tag_without_error_wrapping(options, html_options) @@ -282,7 +282,7 @@ module ActionView alias_method :to_time_select_tag_without_error_wrapping, :to_time_select_tag def to_time_select_tag(options = {}, html_options = {}) - if object.respond_to?("errors") && object.errors.respond_to?("on") + if object.respond_to?(:errors) && object.errors.respond_to?(:on) error_wrapping(to_time_select_tag_without_error_wrapping(options, html_options), object.errors.on(@method_name)) else to_time_select_tag_without_error_wrapping(options, html_options) @@ -298,7 +298,7 @@ module ActionView end def column_type - object.send("column_for_attribute", @method_name).type + object.send(:column_for_attribute, @method_name).type end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 623ed1e8df..a926599e25 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -104,7 +104,7 @@ module ActionView ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public" JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts" STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets" - JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].map(&:to_s).freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) + JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) # 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 @@ -463,7 +463,8 @@ module ActionView end private - COMPUTED_PUBLIC_PATHS = ActiveSupport::Cache::MemoryStore.new.silence! + COMPUTED_PUBLIC_PATHS = {} + COMPUTED_PUBLIC_PATHS_GUARD = Mutex.new # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL @@ -483,23 +484,24 @@ module ActionView dir, source, ext, include_host ].join end - source = COMPUTED_PUBLIC_PATHS.fetch(cache_key) do - begin - source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")) - - if source =~ %r{^[-a-z]+://} - source - else - source = "/#{dir}/#{source}" unless source[0] == ?/ - if has_request - unless source =~ %r{^#{ActionController::Base.relative_url_root}/} - source = "#{ActionController::Base.relative_url_root}#{source}" + COMPUTED_PUBLIC_PATHS_GUARD.synchronize do + source = COMPUTED_PUBLIC_PATHS[cache_key] ||= + begin + source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")) + + if source =~ %r{^[-a-z]+://} + source + else + source = "/#{dir}/#{source}" unless source[0] == ?/ + if has_request + unless source =~ %r{^#{ActionController::Base.relative_url_root}/} + source = "#{ActionController::Base.relative_url_root}#{source}" + end end - end - rewrite_asset_path(source) + rewrite_asset_path(source) + end end - end end if include_host && source !~ %r{^[-a-z]+://} diff --git a/actionpack/lib/action_view/helpers/benchmark_helper.rb b/actionpack/lib/action_view/helpers/benchmark_helper.rb index 743d1d40ec..bd72cda700 100644 --- a/actionpack/lib/action_view/helpers/benchmark_helper.rb +++ b/actionpack/lib/action_view/helpers/benchmark_helper.rb @@ -15,15 +15,15 @@ module ActionView # <%= expensive_files_operation %> # <% end %> # - # That would add something like "Process data files (0.34523)" to the log, + # That would add something like "Process data files (345.2ms)" 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 value is :info. def benchmark(message = "Benchmarking", level = :info) if controller.logger - real = Benchmark.realtime { yield } - controller.logger.send(level, "#{message} (#{'%.5f' % real})") + seconds = Benchmark.realtime { yield } + controller.logger.send(level, "#{message} (#{'%.1f' % (seconds * 1000)}ms)") else yield end diff --git a/actionpack/lib/action_view/helpers/form_country_helper.rb b/actionpack/lib/action_view/helpers/form_country_helper.rb deleted file mode 100644 index 84e811f61d..0000000000 --- a/actionpack/lib/action_view/helpers/form_country_helper.rb +++ /dev/null @@ -1,92 +0,0 @@ -require 'action_view/helpers/form_options_helper' - -module ActionView - module Helpers - module FormCountryHelper - - # Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags. - def country_select(object, method, priority_countries = nil, options = {}, html_options = {}) - InstanceTag.new(object, method, self, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options) - end - - # Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to - # have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so - # that they will be listed above the rest of the (long) list. - # - # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. - def country_options_for_select(selected = nil, priority_countries = nil) - country_options = "" - - if priority_countries - country_options += options_for_select(priority_countries, selected) - country_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n" - end - - return country_options + options_for_select(COUNTRIES, selected) - end - - private - - # All the countries included in the country_options output. - COUNTRIES = ["Afghanistan", "Aland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", - "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", - "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", - "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil", - "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", - "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", - "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", - "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", - "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", - "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", - "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia", - "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea", - "Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Holy See (Vatican City State)", - "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq", - "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", - "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan", - "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya", - "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, The Former Yugoslav Republic Of", - "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique", - "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of", - "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", - "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", - "Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", - "Palestinian Territory, Occupied", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", - "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", - "Rwanda", "Saint Barthelemy", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia", - "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", - "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", - "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", - "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname", - "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic", - "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste", - "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", - "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", - "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", - "Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara", - "Yemen", "Zambia", "Zimbabwe"] unless const_defined?("COUNTRIES") - end - - class InstanceTag #:nodoc: - include FormCountryHelper - - def to_country_select_tag(priority_countries, options, html_options) - html_options = html_options.stringify_keys - add_default_name_and_id(html_options) - value = value(object) - content_tag("select", - add_options( - country_options_for_select(value, priority_countries), - options, value - ), html_options - ) - end - end - - class FormBuilder - def country_select(method, priority_countries = nil, options = {}, html_options = {}) - @template.country_select(@object_name, method, priority_countries, objectify_options(options), @default_options.merge(html_options)) - end - end - end -end
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 9aae945408..33f8aaf9ed 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -324,9 +324,6 @@ module ActionView value == selected end end - - # All the countries included in the country_options output. - COUNTRIES = ActiveSupport::Deprecation::DeprecatedConstantProxy.new 'COUNTRIES', 'ActionView::Helpers::FormCountryHelper::COUNTRIES' end class InstanceTag #:nodoc: diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index e8ca02d760..294c22521e 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -116,7 +116,7 @@ module ActionView # Creates a label field # - # ==== Options + # ==== Options # * Creates standard HTML attributes for the tag. # # ==== Examples @@ -155,10 +155,10 @@ module ActionView # 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: # - # <%= form_tag { :action => "post" }, { :multipart => true } %> + # <% form_tag '/upload', :multipart => true do %> # <label for="file">File to Upload</label> <%= file_field_tag "file" %> # <%= submit_tag %> - # <%= end_form_tag %> + # <% end %> # # The specified URL will then be passed a File object containing the selected file, or if the field # was left blank, a StringIO object. @@ -351,19 +351,16 @@ module ActionView disable_with = "this.value='#{disable_with}'" disable_with << ";#{options.delete('onclick')}" if options['onclick'] - options["onclick"] = [ - "this.setAttribute('originalValue', this.value)", - "this.disabled=true", - disable_with, - "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit())", - "if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false }", - "return result;", - ].join(";") + options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }" + options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }" + options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};" + options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());" + options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" end if confirm = options.delete("confirm") options["onclick"] ||= '' - options["onclick"] += "return #{confirm_javascript_function(confirm)};" + options["onclick"] << "return #{confirm_javascript_function(confirm)};" end tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys) @@ -374,6 +371,9 @@ module ActionView # <tt>source</tt> is passed to AssetTagHelper#image_path # # ==== Options + # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm + # prompt with the question specified. If the user accepts, the form is + # processed normally, otherwise no action is taken. # * <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. # @@ -390,6 +390,13 @@ module ActionView # 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 = {}) + options.stringify_keys! + + if confirm = options.delete("confirm") + options["onclick"] ||= '' + options["onclick"] += "return #{confirm_javascript_function(confirm)};" + end + tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys) end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index ff83494e94..ff41a6d417 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -255,6 +255,14 @@ module ActionView link_to_function(name, remote_function(options), html_options || options.delete(:html)) end + # Creates a button with an onclick event which calls a remote action + # via XMLHttpRequest + # The options for specifying the target with :url + # and defining callbacks is the same as link_to_remote. + def button_to_remote(name, options = {}, html_options = {}) + button_to_function(name, remote_function(options), html_options) + end + # Periodically calls the specified url (<tt>options[:url]</tt>) every # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to # update a specified div (<tt>options[:update]</tt>) with the results @@ -588,26 +596,8 @@ module ActionView private def include_helpers_from_context - unless generator_methods_module = @context.instance_variable_get(:@__javascript_generator_methods__) - modules = @context.extended_by - ([ActionView::Helpers] + ActionView::Helpers.included_modules) - - generator_methods_module = Module.new do - modules.each do |mod| - begin - include mod - rescue Exception => e - # HACK: Probably not a good idea to suppress these warnings - # AFAIK exceptions are only raised in while testing with mocha - # because the module does not like to be included into other - # non TestUnit classes - end - end - include GeneratorMethods - end - @context.instance_variable_set(:@__javascript_generator_methods__, generator_methods_module) - end - - extend generator_methods_module + extend @context.helpers if @context.respond_to?(:helpers) + extend GeneratorMethods end # JavaScriptGenerator generates blocks of JavaScript code that allow you @@ -624,7 +614,7 @@ module ActionView # Example: # # # Generates: - # # new Element.insert("list", { bottom: <li>Some item</li>" }); + # # new Element.insert("list", { bottom: "<li>Some item</li>" }); # # new Effect.Highlight("list"); # # ["status-indicator", "cancel-link"].each(Element.hide); # update_page do |page| @@ -1070,7 +1060,7 @@ module ActionView js_options['asynchronous'] = options[:type] != :synchronous js_options['method'] = method_option_to_s(options[:method]) if options[:method] - js_options['insertion'] = options[:position].to_s.downcase if options[:position] + js_options['insertion'] = "'#{options[:position].to_s.downcase}'" if options[:position] js_options['evalScripts'] = options[:script].nil? || options[:script] if options[:form] diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 9bb235175e..0cdb70e217 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -49,9 +49,9 @@ module ActionView # def content_tag_for(tag_name, record, *args, &block) prefix = args.first.is_a?(Hash) ? nil : args.shift - options = args.first.is_a?(Hash) ? args.shift : {} - concat content_tag(tag_name, capture(&block), - options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })) + options = args.extract_options! + options.merge!({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) }) + content_tag(tag_name, options, &block) end end end diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 637caf203b..435ba936e1 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -1,5 +1,14 @@ require 'action_view/helpers/tag_helper' -require 'html/document' + +begin + require 'html/document' +rescue LoadError + html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner" + if File.directory?(html_scanner_path) + $:.unshift html_scanner_path + require 'html/document' + end +end module ActionView module Helpers #:nodoc: diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index b938c1a801..1d01dafd0e 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -95,7 +95,7 @@ module ActionView # * <tt>:containment</tt> - Takes an element or array of elements to treat as # potential drop targets (defaults to the original target element). # - # * <tt>:only</tt> - A CSS class name or arry of class names used to filter + # * <tt>:only</tt> - A CSS class name or array of class names used to filter # out child elements as candidates. # # * <tt>:scroll</tt> - Determines whether to scroll the list during drag diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index f9096d0029..ab1fdc80bc 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -1,5 +1,14 @@ require 'action_view/helpers/tag_helper' -require 'html/document' + +begin + require 'html/document' +rescue LoadError + html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner" + if File.directory?(html_scanner_path) + $:.unshift html_scanner_path + require 'html/document' + end +end module ActionView module Helpers #:nodoc: @@ -289,7 +298,7 @@ module ActionView "" else textilized = RedCloth.new(text, [ :hard_breaks ]) - textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=") + textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=) textilized.to_html end end @@ -439,8 +448,10 @@ module ActionView # array every time it is called. This can be used for example, to alternate # 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. + # named cycle. The default name for a cycle without a +:name+ key is + # <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle + # and passing the name of the cycle. The current cycle string can be obtained + # anytime using the current_cycle method. # # ==== Examples # # Alternate CSS classes for even and odd numbers... @@ -487,6 +498,23 @@ module ActionView return cycle.to_s end + # Returns the current cycle string after a cycle has been started. Useful + # for complex table highlighing or any other design need which requires + # the current cycle string in more than one place. + # + # ==== Example + # # Alternate background colors + # @items = [1,2,3,4] + # <% @items.each do |item| %> + # <div style="background-color:<%= cycle("red","white","blue") %>"> + # <span style="background-color:<%= current_cycle %>"><%= item %></span> + # </div> + # <% end %> + def current_cycle(name = "default") + cycle = get_cycle(name) + cycle.current_value unless cycle.nil? + end + # 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. # @@ -523,11 +551,29 @@ module ActionView @index = 0 end + def current_value + @values[previous_index].to_s + end + def to_s value = @values[@index].to_s - @index = (@index + 1) % @values.size + @index = next_index return value end + + private + + def next_index + step_index(1) + end + + def previous_index + step_index(-1) + end + + def step_index(n) + (@index + n) % @values.size + end end private |