# Form helpers provide a number of methods to simplify the creation of HTML forms. # They can work directly with models (bound) or standalone (unbound). module Merb::Helpers::Form def _singleton_form_context @_singleton_form_context ||= self._form_class.new(nil, nil, self) end def form_contexts @_form_contexts ||= [] end def current_form_context form_contexts.last || _singleton_form_context end def _new_form_context(name, builder) if name.is_a?(String) || name.is_a?(Symbol) ivar = instance_variable_get("@#{name}") else ivar, name = name, name.class.to_s.snake_case end builder ||= current_form_context.class if current_form_context (builder || self._form_class).new(ivar, name, self) end def with_form_context(name, builder) form_contexts.push(_new_form_context(name, builder)) ret = yield form_contexts.pop ret end # Generates a form tag, which accepts a block that is not directly based on resource attributes # # ==== Parameters # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Notes # * Block helpers use the <%= =%> syntax # * a multipart enctype is automatically set if the form contains a file upload field # # ==== Example # <%= form :action => url(:controller => "foo", :action => "bar", :id => 1) do %> # <%= text_field :name => "first_name", :label => "First Name" %> # <%= submit "Create" %> # <% end =%> # # Generates the HTML: # #
# # # #
def form(*args, &blk) _singleton_form_context.form(*args, &blk) end # Generates a resource specific form tag which accepts a block, this also provides automatic resource routing. # # ==== Parameters # name:: Model or Resource # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Notes # * Block helpers use the <%= =%> syntax # # ==== Example # <%= form_for @person do %> # <%= text_field :first_name, :label => "First Name" %> # <%= text_field :last_name, :label => "Last Name" %> # <%= submit "Create" %> # <% end =%> # # The HTML generated for this would be: # #
# # # # # #
def form_for(name, attrs = {}, &blk) with_form_context(name, attrs.delete(:builder)) do current_form_context.form(attrs, &blk) end end # Creates a scope around a specific resource object like form_for, but doesnt create the form tags themselves. # This makes fields_for suitable for specifying additional resource objects in the same form. # # ==== Examples # <%= form_for @person do %> # <%= text_field :first_name, :label => "First Name" %> # <%= text_field :last_name, :label => "Last Name" %> # <% fields_for :permission do %> # <%= check_box :is_admin, :label => "Administrator" %> # <% end %> # <%= submit "Create" %> # <% end =%> def fields_for(name, attrs = {}, &blk) attrs ||= {} with_form_context(name, attrs.delete(:builder)) do current_form_context.concat(attrs, &blk) end end # Provides the ability to create quick fieldsets as blocks for your forms. # # ==== Parameters # attrs:: HTML attributes and options # # ==== Options # +legend+:: Adds a legend tag within the fieldset # # ==== Returns # String:: HTML # # ==== Notes # Block helpers use the <%= =%> syntax # # ==== Example # <%= fieldset :legend => "Customer Options" do %> # ...your form elements # <% end =%> # # Generates the HTML: # #
# Customer Options # ...your form elements #
def fieldset(attrs = {}, &blk) _singleton_form_context.fieldset(attrs, &blk) end def fieldset_for(name, attrs = {}, &blk) with_form_context(name, attrs.delete(:builder)) do current_form_context.fieldset(attrs, &blk) end end # Provides a generic HTML label. # # ==== Parameters # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= label "Full Name", :for => "name" %> # => def label(*args) current_form_context.label(*args) end # Provides a HTML text input tag # # ==== Parameters # name:: Model or Resource # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= text_field :name => :fav_color, :label => "Your Favorite Color" %> # # => # # Used with a model: # # <%= form_for @person do %> # <%= text_field :first_name, :label => "First Name" %> # <% end =%> def text_field; end # Provides a HTML password input. # # ==== Parameters # name:: Model or Resource # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= password_field :name => :password, :label => "Password" %> # # => # # Used with a model: # # <%= password_field :password, :label => 'New Password' %> def password_field; end # Provides a HTML hidden input field # # ==== Parameters # name:: Model or Resource # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= hidden_field :name => "secret", :value => "some secret value" %> # # Used with a model: # # <%= hidden_field :identifier %> # # => def hidden_field; end # Provides a HTML file input # # ==== Parameters # name:: Model or Resource # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= file_field :name => "file", :label => "File" %> # # Used with a model: # # <%= file_field :file, :label => "Choose a file" %> def file_field; end # Provides a HTML textarea tag # # ==== Parameters # contents:: Contents of the text area # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= text_area "my comments", :name => "comments" %> # # Used with a model: # # <%= text_area :comments %> def text_area; end # Provides a HTML select # # ==== Parameters # method:: Resource attribute # attrs:: HTML attributes and options # # ==== Options # +prompt+:: Adds an additional option tag with the provided string with no value. # +selected+:: The value of a selected object, which may be either a string or an array. # +include_blank+:: Adds an additional blank option tag with no value. # +collection+:: The collection for the select options # +text_method+:: Method to determine text of an option (as a symbol). Ex: :text_method => :name will call .name on your record object for what text to display. # +value_method+:: Method to determine value of an option (as a symbol). # # ==== Returns # String:: HTML # # ==== Example # <%= select :name, :collection => %w(one two three) %> def select; end # Provides a generic HTML checkbox input tag. # There are two ways this tag can be generated, based on the # option :boolean. If not set to true, a "magic" input is generated. # Otherwise, an input is created that can be easily used for passing # an array of values to the application. # # ==== Parameters # method:: Resource attribute # attrs:: HTML attributes and options # # ==== Returns # String:: HTML # # ==== Example # <%= check_box :name => "is_activated", :value => "1" %> # <%= check_box :name => "choices[]", :boolean => false, :value => "dog" %> # <%= check_box :name => "choices[]", :boolean => false, :value => "cat" %> # <%= check_box :name => "choices[]", :boolean => false, :value => "weasle" %> # # Used with a model: # # <%= check_box :is_activated, :label => "Activated?" %> def check_box; end # Provides a HTML radio input tag # # ==== Parameters # method:: Resource attribute # attrs:: HTML attributes and options # # ==== Returns # String:: HTML # # ==== Example # <%= radio_button :name => "radio_options", :value => "1", :label => "One" %> # <%= radio_button :name => "radio_options", :value => "2", :label => "Two" %> # <%= radio_button :name => "radio_options", :value => "3", :label => "Three", :checked => true %> # # Used with a model: # # <%= form_for @person do %> # <%= radio_button :first_name %> # <% end =%> def radio_button; end # Provides a radio group based on a resource attribute. # This is generally used within a resource block such as +form_for+. # # ==== Parameters # method:: Resource attribute # arr:: Choices # # ==== Returns # String:: HTML # # ==== Examples # <%# the labels are the options %> # <%= radio_group :my_choice, [5,6,7] %> # # <%# custom labels %> # <%= radio_group :my_choice, [{:value => 5, :label => "five"}] %> def radio_group; end # @todo radio_group helper still needs to be implemented %w(text_field password_field hidden_field file_field text_area select check_box radio_button radio_group).each do |kind| self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{kind}(*args) if bound?(*args) current_form_context.bound_#{kind}(*args) else current_form_context.unbound_#{kind}(*args) end end RUBY end # Generates a HTML button. # # ==== Parameters # contents:: HTML contained within the button tag # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Notes # * Buttons do not always work as planned in IE # http://www.peterbe.com/plog/button-tag-in-IE # * Not all mobile browsers support buttons # http://nickcowie.com/2007/time-to-stop-using-the-button-element/ # # ==== Example # <%= button "Initiate Launch Sequence" %> def button(contents, attrs = {}) current_form_context.button(contents, attrs) end # Generates a HTML submit button. # # ==== Parameters # value:: Sets the value="" attribute # attrs:: HTML attributes # # ==== Returns # String:: HTML # # ==== Example # <%= submit "Process" %> def submit(contents, attrs = {}) current_form_context.submit(contents, attrs) end # Provides a HTML formatted display of resource errors in an unordered list with a h2 form submission error # # ==== Parameters # obj:: Model or Resource # error_class:: CSS class to use for error container # build_li:: Custom li tag to wrap each error in # header:: Custom header text for the error container # before:: Display the errors before or inside of the form # # ==== Returns # String:: HTML # # ==== Examples # <%= error_messages_for :person %> # <%= error_messages_for :person {|errors| "You can has probs nao: #{errors.size} of em!"} # <%= error_messages_for :person, lambda{|error| "
  • #{error.join(' ')}"} %> # <%= error_messages_for :person, nil, 'bad_mojo' %> def error_messages_for(obj = nil, opts = {}) current_form_context.error_messages_for(obj, opts[:error_class] || "error", opts[:build_li] || "
  • %s
  • ", opts[:header] || "

    Form submission failed because of %s problem%s

    ", opts.key?(:before) ? opts[:before] : true) end alias error_messages error_messages_for private def bound?(*args) args.first.is_a?(Symbol) end end