require 'securerandom'
module Padrino
module Helpers
##
# Helpers related to producing form related tags and inputs into templates.
#
module FormHelpers
##
# Constructs a form for object using given or default form_builder
#
# @param [Object] object
# The object for which the form is being built.
# @param [String] url
# The url this form will submit to.
# @param [Hash] settings
# The settings associated with this form. Accepts html options.
# @option settings [String] :builder ("StandardFormBuilder")
# The FormBuilder class to use such as StandardFormBuilder.
# @param [Proc] block
# The fields and content inside this form.
#
# @yield [AbstractFormBuilder] The form builder used to compose fields.
#
# @return [String] The html object-backed form with the specified options and input fields.
#
# @example
# form_for :user, '/register' do |f| ... end
# form_for @user, '/register', :id => 'register' do |f| ... end
#
# @api public
def form_for(object, url, settings={}, &block)
instance = builder_instance(object, settings)
html = capture_html(instance, &block)
form_tag(url, settings) { html }
end
##
# Constructs form fields for an object using given or default form_builder
# Used within an existing form to allow alternate objects within one form
#
# @param [Object] object
# The object for which the fields are being built.
# @param [Hash] settings
# The settings associated with these fields. Accepts html options.
# @param [Proc] block
# The content inside this set of fields.
#
# @return [String] The html fields with the specified options.
#
# @example
# fields_for @user.assignment do |assignment| ... end
# fields_for :assignment do |assigment| ... end
#
# @api public
def fields_for(object, settings={}, &block)
instance = builder_instance(object, settings)
fields_html = capture_html(instance, &block)
fields_html << instance.hidden_field(:id) if instance.send(:nested_object_id)
concat_safe_content fields_html
end
##
# Constructs a form without object based on options
#
# @param [String] url
# The url this form will submit to.
# @param [Hash] options
# The html options associated with this form.
# @param [Proc] block
# The fields and content inside this form.
#
# @return [String] The html form with the specified options and input fields.
#
# @example
# form_tag '/register', :class => "registration_form" do ... end
#
# @api public
def form_tag(url, options={}, &block)
desired_method = options[:method].to_s
options.delete(:method) unless desired_method =~ /get|post/i
options.reverse_merge!(:method => 'post', :action => url)
options[:enctype] = 'multipart/form-data' if options.delete(:multipart)
options['accept-charset'] ||= 'UTF-8'
inner_form_html = hidden_form_method_field(desired_method)
inner_form_html << csrf_token_field
inner_form_html << mark_safe(capture_html(&block))
concat_content content_tag(:form, inner_form_html, options)
end
##
# Returns the hidden method field for 'put' and 'delete' forms
# Only 'get' and 'post' are allowed within browsers;
# 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
#
# @param [String] desired_method
# The method this hidden field represents (i.e put or delete))
#
# @return [String] The hidden field representing the +desired_method+ for the form.
#
# @example
# # Generate:
# hidden_form_method_field('delete')
#
# @api semipublic
def hidden_form_method_field(desired_method)
return ActiveSupport::SafeBuffer.new if desired_method.blank? || desired_method.to_s =~ /get|post/i
hidden_field_tag(:_method, :value => desired_method)
end
##
# Constructs a field_set to group fields with given options
#
# @overload field_set_tag(legend=nil, options={}, &block)
# @param [String] legend The legend caption for the fieldset
# @param [Hash] options The html options for the fieldset.
# @param [Proc] block The content inside the fieldset.
# @overload field_set_tag(options={}, &block)
# @param [Hash] options The html options for the fieldset.
# @param [Proc] block The content inside the fieldset.
#
# @return [String] The html for the fieldset tag based on given +options+.
#
# @example
# field_set_tag(:class => "office-set") { }
# field_set_tag("Office", :class => 'office-set') { }
#
# @api public
def field_set_tag(*args, &block)
options = args.extract_options!
legend_text = args[0].is_a?(String) ? args.first : nil
legend_html = legend_text.blank? ? ActiveSupport::SafeBuffer.new : content_tag(:legend, legend_text)
field_set_content = legend_html + mark_safe(capture_html(&block))
concat_content content_tag(:fieldset, field_set_content, options)
end
##
# Constructs list html for the errors for a given symbol
#
# @overload error_messages_for(*objects, options = {})
# @param [Array