diff --git a/lib/ramaze/gestalt.rb b/lib/ramaze/gestalt.rb index caa1ee03..9427b2be 100644 --- a/lib/ramaze/gestalt.rb +++ b/lib/ramaze/gestalt.rb @@ -69,11 +69,39 @@ def p(*args, &block) end ## - # Workaround for Kernel#select to make work. + # Workaround for @g.table in BlueForm using method/call. + # This is needed in order to use m = g.method("table") etc. # - # @param [Array] args Extra arguments that should be processed before - # creating the select tag. - # @param [Proc] block + def table(*args, &block) + _gestalt_call_tag :table, args, &block + end + + ## + # Workaround for @g.tr in BlueForm using method/call. + # This is needed in order to use m = g.method("tr") etc. + # + def tr(*args, &block) + _gestalt_call_tag :tr, args, &block + end + + ## + # Workaround for @g.th in BlueForm using method/call. + # This is needed in order to use m = g.method("th") etc. + # + def th(*args, &block) + _gestalt_call_tag :th, args, &block + end + + ## + # Workaround for @g.td in BlueForm using method/call. + # This is needed in order to use m = g.method("td") etc. + # + def td(*args, &block) + _gestalt_call_tag :td, args, &block + end + + ## + # Workaround for Kernel#select to make work. # def select(*args, &block) _gestalt_call_tag(:select, args, &block) @@ -137,7 +165,7 @@ def _gestalt_escape_entities(s) end ## - # Shortcut for building tags, + # Shortcut for building tags. # # @param [String] name # @param [Array] args @@ -147,6 +175,15 @@ def tag(name, *args, &block) _gestalt_call_tag(name.to_s, args, &block) end + ## + # A way to append text to the output of Gestalt. + # + # @param [String] text + # + def <<(str) + @out << str + end + ## # Convert the final output of Gestalt to a string. # This method has the following alias: "to_str". diff --git a/lib/ramaze/helper/blue_form.rb b/lib/ramaze/helper/blue_form.rb index 5560be1e..1014fcac 100644 --- a/lib/ramaze/helper/blue_form.rb +++ b/lib/ramaze/helper/blue_form.rb @@ -23,6 +23,7 @@ module Helper # # form_for(@data, :method => :post) do |f| # f.input_text 'Username', :username + # f.input_password 'Password', :password # end # # The object comes handy when you want to do server-side form validation: @@ -82,15 +83,29 @@ module BlueForm # called using a block and it's return value should be manually sent to # the browser (since it does not echo the value). # - # @param [Object] form_values Object containing the values for each form - # field. + # @param [Object] form_object Object containing the values for each form + # field. If the object contains a hash of the form {:field=>"error"} it + # will be used to generate error messages in the BlueForm output. # @param [Hash] options Hash containing any additional form attributes - # such as the method, action, enctype and so on. + # such as the method, action, enctype and so on. To choose an + # arrangement of paragraph, table, or none, use + # :arrangement=>:paragraph, et.al. # @param [Block] block Block containing the elements of the form such as # password fields, textareas and so on. # - def form_for(form_values, options = {}, &block) - form = Form.new(form_values, options) + def form_for(form_object, options = {}, &block) + form = Form.new(form_object, options) + case + when form_object.nil? + # There is no form object, therefore, no errors + when !form_object.respond_to?(:errors) + # There is a form object, but it has no errors field + when !form_object.errors.is_a?(Hash) + # There is an errors object, but it's not a Hash so ignore it + else + # There is a form object, and it has a Hash errors field + form_errors.merge!(form_object.errors) + end form.build(form_errors, &block) form end @@ -145,6 +160,47 @@ def form_errors_from_model(obj) end end + ## + # Class BlueFormModel contains a mass copy method like Sequel's that + # can be used to create objects for 'form_for' that are not + # database models, but have this one mass assignment + # method in them. + # + # @example + # class Login < BlueFormModel + # :attr_accessor :username, :password, :confirm + # end + # + # login = Login.new + # login.set_fields(session.request.params, [:username,:password,:confirm]) + # + # @caveat + # Any use of 'BlueFormModel' must FOLLOW the 'helper :blue_form' + # statement in your code (which loads it). + # + class BlueFormModel + attr_accessor :errors + def initialize + @errors = {} + end + def valid? + @errors.empty? + end + def set_fields(hash, fields, opts={}) + fields.each do |f| + if hash.has_key?(f) + instance_variable_set("@#{f}", hash[f]) + elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s) + instance_variable_set("@#{sf}", hash[sf]) + else + raise NoMethodError.new("undefined method `#{f.to_s}=' for #{self.inspect}") \ + if opts[:missing]!=:skip + end + end + self + end + end + ## # Main form class that contains all the required methods to generate form # specific tags, such as textareas and select boxes. Do note that this @@ -153,22 +209,31 @@ def form_errors_from_model(obj) # class Form attr_reader :g - attr_reader :form_values + attr_reader :form_object ## # Constructor method that generates an instance of the Form class. # - # @param [Object] form_values Object containing the values for each form + # @param [Object] form_object Object containing the values for each form # field. # @param [Hash] options A hash containing any additional form attributes. # @return [Object] An instance of the Form class. # - def initialize(form_values, options) - @form_values = form_values + def initialize(form_object, options) + @form_object = form_object + @arrangement = options.delete(:arrangement) + @arrangement = :paragraph if ([:table,:paragraph,:none].index(@arrangement)).nil? @form_args = options.dup @g = Gestalt.new end + ## + # Placeholder when no wrapper tag is used + # + def nul(*args) + yield + end + ## # Builds the form by generating the opening/closing tags and executing # the methods in the block. @@ -181,16 +246,31 @@ def build(form_errors = {}) @form_errors = {} form_errors.each do |key, value| - if value.respond_to?(:first) - value = value.first - end - + value = value.first if value.respond_to?(:first) @form_errors[key.to_s] = value end @g.form(@form_args) do if block_given? - yield self + case @arrangement + when :paragraph + @table_wrapper = self.method('nul') + @paragraph_wrapper = @g.method('p') + @label_wrapper = self.method('nul') + @input_wrapper = self.method('nul') + when :table + @table_wrapper = @g.method('table') + @paragraph_wrapper = @g.method('tr') + @label_wrapper = @g.method('th') + @input_wrapper = @g.method('td') + when :none + @table_wrapper = self.method('nul') + @paragraph_wrapper = self.method('nul') + @label_wrapper = self.method('nul') + @input_wrapper = self.method('nul') + end + @hidden_wrapper = self.method('nul') + @table_wrapper.call { yield(self) } end end end @@ -224,87 +304,22 @@ def fieldset(&block) end ## - # Generate an input tag with a type of "text" along with a label tag. - # This method also has the alias "text" so feel free to use that one - # instead of input_text. - # - # @param [String] label The text to display inside the label tag. - # @param [String Symbol] name The name of the text field. - # @param [Hash] args Any additional HTML attributes along with their - # values. - # @example - # form_for(@data, :method => :post) do |f| - # f.input_text 'Username', :username - # end - # - def input_text(label, name, args = {}) - # The ID can come from 2 places, id_for and the args hash - id = args[:id] ? args[:id] : id_for(name) - args = args.merge(:type => :text, :name => name, :id => id) - - if !args[:value] and @form_values.respond_to?(name) - args[:value] = @form_values.send(name) - end - - @g.p do - label_for(id, label, name) - @g.input(args) - end - end - alias text input_text - - ## - # Generate an input tag with a type of "password" along with a label. - # Password fields are pretty much the same as text fields except that - # the content of these fields is replaced with dots. This method has the - # following alias: "password". - # - # @param [String] label The text to display inside the label tag. - # @param [String Symbol] name The name of the password field. - # @param [Hash] args Any additional HTML attributes along with their - # values. - # @example - # form_for(@data, :method => :post) do |f| - # f.input_password 'My password', :password - # end - # - def input_password(label, name, args = {}) - # The ID can come from 2 places, id_for and the args hash - id = args[:id] ? args[:id] : id_for(name) - args = args.merge(:type => :password, :name => name, :id => id) - - if !args[:value] and @form_values.respond_to?(name) - args[:value] = @form_values.send(name) - end - - @g.p do - label_for(id, label, name) - @g.input(args) - end - end - alias password input_password - - ## - # Generate a submit tag (without a label). A submit tag is a button that - # once it's clicked will send the form data to the server. + # Generate a button tag (without a label). A button tag is a button that + # once it's clicked will call a javascript function. # # @param [String] value The text to display in the button. # @param [Hash] args Any additional HTML attributes along with their # values. # @example # form_for(@data, :method => :post) do |f| - # f.input_submit 'Save' + # f.input_button 'Press', :onclick=>"msg()" # end # - def input_submit(value = nil, args = {}) - args = args.merge(:type => :submit) - args[:value] = value unless value.nil? - - @g.p do - @g.input(args) - end - end - alias submit input_submit + def input_button(value = nil, args = {}) + args[:value] = value if value + tag(:button, nil, args) + end # def input_button + alias button input_button ## # Generate an input tag with a type of "checkbox". @@ -353,112 +368,167 @@ def input_submit(value = nil, args = {}) # to false will hide it. # def input_checkbox(label, name, checked = nil, args = {}) - id = args[:id] ? args[:id] : "#{id_for(name)}_0" - - # Determine whether or not to show the value of the checkbox - if args.key?(:show_value) - show_value = args.delete(:show_value) - else - show_value = true - end - - # Determine whether or not to show the label - if args.key?(:show_label) - show_label = args.delete(:show_label) - else - show_label = true - end - - # Get the checkbox value from either the args hash or from - # the form object (as specified in the form_for() method). - if !args[:values] and @form_values.respond_to?(name) - args[:values] = @form_values.send(name) - end - - # That class for each element wrapper (a span tag) can be customized - # using :span_class => "a_class". - if args[:span_class] - span_class = args[:span_class] - args.delete(:span_class) - else - span_class = "checkbox_wrap" - end - - # Get the type from the args hash instead of pre-defining it. Doing so - # means we can use this method for the input_radio method. - args[:type] = :checkbox if !args[:type] + opts = {} + opts[:label] = label if label + opts[:checked] = checked if checked + opts[:values] = args.delete(:values) if args.has_key?(:values) + opts[:show_value] = args.delete(:show_value) if args.has_key?(:show_value) + opts[:show_label] = args.delete(:show_label) if args.has_key?(:show_label) + opts[:span_class] = args.delete(:span_class) if args.has_key?(:span_class) + type = if args[:type]==:radio then :radio else :checkbox end + tag(type, name, args, opts) + end + alias checkbox input_checkbox - # Convert the values to an array if it's something we can't use in a loop - # (e.g. a string). - if args[:values].class != Hash and args[:values].class != Array - args[:values] = [args[:values]] - end + ## + # Generate an input tag with a type of "color" along with a label tag. + # This method also has the alias "color" so feel free to use that one + # instead of input_color. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the color field. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_color 'Color', :car_color + # end + # + def input_color(label, name, args = {}) + tag(:color, name, args, :label=>label) + end # def input_color + alias color input_color - # Create a checkbox for each value - if !args[:values].empty? - @g.p do - # Let's create the label and the hidden field - if show_label === true - label_for(id, label, name) - end + ## + # Generate a select tag with a size=1, along with the option tags + # and a label. A size=1 attribute creates a dropdown box; otherwise, + # it's the same as a select call. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the select tag. + # @param [Hash] args Hash containing additional HTML attributes. + # @example + # form_for(@data, :method => :post) do |f| + # f.dropdown 'Country', :country_list + # end + # + def input_dropdown(label, name, args = {}) + opts = {} + opts[:label] = label if label + opts[:selected] = args.delete(:selected) if args.has_key?(:selected) + opts[:values] = args.delete(:values) if args.has_key?(:values) + args[:size] = 1 + tag(:select, name, args, opts) + end + alias dropdown input_dropdown - # Loop through all the values. Each checkbox will have an ID of - # "form-NAME-INDEX". Each name will be NAME followed by [] to - # indicate it's an array (since multiple values are possible). - args[:values].each_with_index do |value, index| - id = args[:id] ? args[:id] : "#{id_for(name)}_#{index}" + ## + # Generate a email text box. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the email. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.email 'E-Mail', :email + # end + # + def input_email(label, name, args = {}) + tag(:email, name, args, :label=>label) + end # def email + alias email input_email - if args[:type] == :checkbox - checkbox_name = "#{name}[]" - else - checkbox_name = name - end + ## + # Generate a field for uploading files. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the radio tag. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_file 'Image', :image + # end + # + def input_file(label, name, args = {}) + tag(:file, name, args, :label=>label) + end + alias file input_file - # Copy all additional attributes and their values except the - # values array. - opts = args.clone - opts.delete(:values) + ## + # Generate a hidden field. Hidden fields are essentially the same as + # text fields except that they aren't displayed in the browser. + # + # @param [String Symbol] name The name of the hidden field tag. + # @param [String] value The value of the hidden field + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_hidden :user_id + # end + # + def input_hidden(name, value = nil, args = {}) + args[:value] = value unless value.nil? + tag(:hidden, name, args) + end + alias hidden input_hidden - # Get the value and text to display for each checkbox - if value.class == Array - checkbox_text = value[0] - checkbox_value = value[1] - else - checkbox_text = checkbox_value = value - end + ## + # Generate a image tag. An image tag is a submit button that + # once it's clicked will send the form data to the server. + # + # @param [String] value The text to display in the button. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_image 'Save' + # end + # + def input_image(src, args = {}) + args[:src] = src unless src.nil? + tag(:image, nil, args) + end + alias image input_image - # Let's see if the current item is checked - if checked.class == Array - if checked.include?(checkbox_value) - opts[:checked] = 'checked' - end - else - if checkbox_value == checked - opts[:checked] = 'checked' - end - end + ## + # Generate a number in a click box. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the number. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.number 'Age', :age, :min=>1, :max=>120 + # end + # + def input_number(label, name, args = {}) + tag(:number, name, args, :label=>label) + end # def number + alias number input_number - # And we're done, easy wasn't it? - opts = opts.merge( - :name => checkbox_name, :id => id, :value => checkbox_value - ) - - # Generate the following HTML: - # - # - # #{value} - # - # - @g.span(:class => span_class) do - @g.input(opts) - " #{checkbox_text}" if show_value === true - end - end - end - end + ## + # Generate an input tag with a type of "password" along with a label. + # Password fields are pretty much the same as text fields except that + # the content of these fields is replaced with dots. This method has the + # following alias: "password". + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the password field. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_password 'My password', :password + # end + # + def input_password(label, name, args = {}) + tag(:password, name, args, :label=>label) end - alias checkbox input_checkbox + alias password input_password ## # Generate an input tag with a type of "radio". @@ -498,63 +568,103 @@ def input_checkbox(label, name, checked = nil, args = {}) def input_radio(label, name, checked = nil, args = {}) # Force a type of "radio" args[:type] = :radio - - if !args[:span_class] - args[:span_class] = "radio_wrap" - end - + args[:span_class] = "radio_wrap" unless args[:span_class] self.input_checkbox(label, name, checked, args) end alias radio input_radio ## - # Generate a field for uploading files. + # Generate a range with a slider bar. # # @param [String] label The text to display inside the label tag. - # @param [String Symbol] name The name of the radio tag. + # @param [String Symbol] name The name of the range. # @param [Hash] args Any additional HTML attributes along with their # values. # @example # form_for(@data, :method => :post) do |f| - # f.input_file 'Image', :image + # f.range 'Age', :age, :min=>1, :max=>120 # end # - def input_file(label, name, args = {}) - id = args[:id] ? args[:id] : id_for(name) - args = args.merge(:type => :file, :name => name, :id => id) + def input_range(label, name, args = {}) + tag(:range, name, args, :label=>label) + end # def range + alias range input_range - @g.p do - label_for(id, label, name) - @g.input(args) - end + ## + # Generate a reset tag (without a label). A reset tag is a button that + # once it's clicked will reset the form data in the form + # back to it's initial state. + # + # @param [String] value The text to display in the button. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_reset 'Reset! Beware: you will lose the data in your form.' + # end + # + def input_reset(value = nil, args = {}) + args[:value] = value if value + tag(:reset, nil, args) + end # def input_reset + alias reset input_reset + + ## + # Generate a select tag along with the option tags and a label. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the select tag. + # @param [Hash] args Hash containing additional HTML attributes. + # @example + # form_for(@data, :method => :post) do |f| + # f.select 'Country', :country_list + # end + # + def input_select(label, name, args = {}) + opts = {} + opts[:label] = label if label + opts[:selected] = args.delete(:selected) if args.has_key?(:selected) + opts[:values] = args.delete(:values) if args.has_key?(:values) + tag(:select, name, args, opts) end - alias file input_file + alias select input_select ## - # Generate a hidden field. Hidden fields are essentially the same as - # text fields except that they aren't displayed in the browser. + # Generate a submit tag (without a label). A submit tag is a button that + # once it's clicked will send the form data to the server. # - # @param [String Symbol] name The name of the hidden field tag. - # @param [String] value The value of the hidden field + # @param [String] value The text to display in the button. # @param [Hash] args Any additional HTML attributes along with their # values. # @example # form_for(@data, :method => :post) do |f| - # f.input_hidden :user_id + # f.input_submit 'Save' # end # - def input_hidden(name, value = nil, args = {}) - args = args.merge(:type => :hidden, :name => name) - - if !value and @form_values.respond_to?(name) - args[:value] = @form_values.send(name) - else - args[:value] = value - end + def input_submit(value = nil, args = {}) + args[:value] = value unless value.nil? + tag(:submit, nil, args) + end + alias submit input_submit - @g.input(args) + ## + # Generate an input tag with a type of "text" along with a label tag. + # This method also has the alias "text" so feel free to use that one + # instead of input_text. + # + # @param [String] label The text to display inside the label tag. + # @param [String Symbol] name The name of the text field. + # @param [Hash] args Any additional HTML attributes along with their + # values. + # @example + # form_for(@data, :method => :post) do |f| + # f.input_text 'Username', :username + # end + # + def input_text(label, name, args = {}) + tag(:text, name, args, :label=>label) end - alias hidden input_hidden + alias text input_text ## # Generate a text area. @@ -568,101 +678,301 @@ def input_hidden(name, value = nil, args = {}) # f.textarea 'Description', :description # end # - def textarea(label, name, args = {}) - id = args[:id] ? args[:id] : id_for(name) - - # Get the value of the textarea - if !args[:value] and @form_values.respond_to?(name) - value = @form_values.send(name) - else - value = args[:value] - args.delete(:value) - end + def input_textarea(label, name, args = {}) + opts = {} + opts[:label] = label if label + opts[:value] = args.delete(:value) if args.has_key?(:value) + tag(:textarea, name, args, opts) + end + alias textarea input_textarea - args = args.merge(:name => name, :id => id) + ## + # Method used for converting the results of the BlueForm helper to a + # string + # + # @return [String] The form output + # + def to_s + @g.to_s + end - @g.p do - label_for(id, label, name) - @g.textarea(args){ value } + ## + # Method used for converting the results of the BlueForm helper to a + # human readable string. This isn't recommended for production because + # it requires much more time to generate the HTML output than to_s. + # + # @return [String] The formatted form output + # + def to_html + # Combine the sub-parts to form whole tags or whole in-between texts + parts = [] + tag = "" + @g.out.each do |fragment| + case + when fragment[0] == '<' + if tag.empty? + tag << fragment + else + parts << tag + tag = fragment + end + when fragment[-1] == '>' + tag << fragment + parts << tag + tag = "" + else + tag << fragment + end # case end + parts << tag if tag + + # output the segments, but adjust the indentation + indent = 0 + html = "" + parts.each do |part| + case + when part[0..1] == '') + # self terminating tag -- no change in indent + when (part[0] == '<') && (part[1] != '/') + indent += 1 + end + end + + # return the formatted string + return html end ## - # Generate a select tag along with the option tags and a label. + # Generate a URL. # # @param [String] label The text to display inside the label tag. - # @param [String Symbol] name The name of the select tag. - # @param [Hash] args Hash containing additional HTML attributes. + # @param [String Symbol] name The name of the url. + # @param [Hash] args Any additional HTML attributes along with their + # values. # @example # form_for(@data, :method => :post) do |f| - # f.select 'Country', :country_list + # f.url 'Description', :description # end # - def select(label, name, args = {}) - id = args[:id] ? args[:id] : id_for(name) - multiple, size = args.values_at(:multiple, :size) + def input_url(label, name, args = {}) + tag(:url, name, args, :label=>label) + end # def url + alias url input_url + +#-------------------------------------------------------------------------------# +#--- GENERATE THE HTML HERE ----------------------------------------------------# +#-------------------------------------------------------------------------------# + + def tag(type, name, args={}, opts={}) + paragraph_wrapper = if type==:hidden then @hidden_wrapper else @paragraph_wrapper end + paragraph_wrapper.call do + + case type + + when :color, :email, :file, :number, :password, :range, :text, :url + args[:type] = type + args[:name] = name unless args.has_key?(:name) || name.nil? + args[:id] = id_for(name) unless args.has_key?(:id) || name.nil? + value = extract_values_from_object(name, args) unless args.has_key?(:value) + args[:value] = value if value + error = if name then @form_errors.delete(name.to_s) else nil end + + @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label) + @input_wrapper.call do + if opts.has_key?(:span_class) + @g.span(accept(opts, [:span_class])) do + @g.input(args) + end + else + @g.input(args) + end + end + @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error - # Get all the values - if !args[:values] and @form_values.respond_to?(name) - values = @form_values.send(name) - else - values = args[:values] - args.delete(:values) - end + when :button, :image, :reset, :submit + args[:type] = type + args[:name] = name unless args.has_key?(:name) || name.nil? + @input_wrapper.call do + @g.input(args) + end - args[:multiple] = 'multiple' if multiple - args[:size] = (size || values.count || 1).to_i - args[:name] = multiple ? "#{name}[]" : name - args = args.merge(:id => id) - - # Retrieve the selected value - has_selected, selected = args.key?(:selected), args[:selected] - selected = [selected] if !selected.is_a?(Array) - args.delete(:selected) - - @g.p do - label_for(id, label, name) - @g.select args do - values.each do |value, o_name| - o_name ||= value - o_args = {:value => value} - - if has_selected and selected.include?(value) - o_args[:selected] = 'selected' + when :textarea + args[:name] = name unless args.has_key?(:name) || name.nil? + args[:id] = id_for(name) unless args.has_key?(:id) + value = extract_values_from_object(name, args) unless opts.has_key?(:value) + opts[:value] = value if value + error = if name then @form_errors.delete(name.to_s) else nil end + + @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label) + @input_wrapper.call do + if opts.has_key?(:span_class) + @g.span(accept(opts, [:span_class])) do + @g.textarea(args) {opts[:value]} + end + else + @g.textarea(args) {opts[:value]} end - - @g.option(o_args){ o_name } end - end - end - end + @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error + + when :hidden + args[:type] = type + args[:name] = name unless args.has_key?(:name) || name.nil? + args[:value] = extract_values_from_object(name, args) unless args.has_key?(:value) + @g.input(args) + + when :checkbox, :radio + args[:type] = type + args[:name] = nil + args[:id] = "#{id_for(name)}_0" unless args.has_key?(:id) + error = if name then @form_errors.delete(name.to_s) else nil end + + # Get the options or their defaults + span_class = if opts.has_key?(:span_class) then opts[:span_class] else "checkbox_wrap" end + show_label = if opts.has_key?(:show_label) then opts[:show_label] else true end + show_value = if opts.has_key?(:show_value) then opts[:show_value] else true end + + # Get all the values or checked from the form object + has_values = opts.has_key?(:values) + has_checked = opts[:checked] + if has_values + values = opts[:values] + if has_checked + checked = opts[:checked] + else + checked = extract_values_from_object(name, args) + end + else + values = extract_values_from_object(name, args) + values = [] if values.nil? + if has_checked + checked = opts[:checked] + else + checked = [] + end + end + values = [values] unless [Array,Hash].index(values.class) + checked = [checked] unless [Array,Hash].index(checked.class) - ## - # Method used for converting the results of the BlueForm helper to a - # string - # - # @return [String] The form output - # - def to_s - @g.to_s - end + # Loop through all the values. Each checkbox will have an ID of + # "form-NAME-INDEX". Each name will be NAME followed by [] to + # indicate it's an array (since multiple values are possible). + @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label) && show_label + @input_wrapper.call do + values.each_with_index do |value,index| + args[:id] = "#{id_for(name)}_#{index}" + + # The id is an array for checkboxes, and elemental for radio buttons + checkbox_name = if type == :checkbox then "#{name}[]" else name end + args[:name] = checkbox_name + + # Get the value and text to display for each checkbox + if value.class == Array + # It's a hash in inverted ([value,key]) order + checkbox_text = value[0] + checkbox_value = value[1] + else + # It's one value of an array + checkbox_text = checkbox_value = value + end + args[:value] = checkbox_value + + # Let's see if the current item is checked + if checked.include?(checkbox_value) + args[:checked] = 'checked' + else + args.delete(:checked) + end + + @g.span(:class=>span_class) do + @g.input(args) + " #{checkbox_text}" if show_value == true + end + end + end # @input_wrapper + @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error + + when :select + id = args[:id] ? args[:id] : id_for(name) + multiple, size = args.values_at(:multiple, :size) + error = if name then @form_errors.delete(name.to_s) else nil end + + # Get all the values or selected from the form object + has_values = opts.has_key?(:values) + has_selected = opts[:selected] + if has_values + values = opts[:values] + if has_selected + selected = opts[:selected] + else + selected = extract_values_from_object(name, args) + end + else + values = extract_values_from_object(name, args) + values = [] if values.nil? + if has_selected + selected = opts[:selected] + else + selected = [] + end + end + values = [values] unless [Array,Hash].index(values.class) + selected = [selected] unless [Array,Hash].index(selected.class) + + args[:multiple] = 'multiple' if multiple + args[:size] = (size || values.count || 1).to_i + args[:name] = multiple ? "#{name}[]" : name + args = args.merge(:id => id) + + @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label) + @input_wrapper.call do + @g.select(args) do + values.each do |value, option_name| + option_name ||= value + option_args = {:value => value} + option_args[:selected] = 'selected' if selected.include?(value) + @g.option(option_args){ option_name } + end # opts[:values].each + end # @g.select + end # @input_wrapper.call + @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error + + else + raise ArgumentError.new("Blueform doesn't support HTML5 type '#{type}'") + end # case + + end # paragraph_wrapper.call + end # tag private ## - # Generate a label based on the id and value. - # - # @param [String] id The ID to which the label belongs. - # @param [String] value The text to display inside the label tag. - # @param [String] name The name of the field to which the label belongs. + # If possible, extract the data from the form object. # - def label_for(id, value, name) - if error = @form_errors.delete(name.to_s) - @g.label("#{value} ", :for => id){ @g.span(:class => :error){ error } } - else - @g.label(value, :for => id) + # @param [String] field_name The name of the field. + # @return [Array] The args parameter. Extract looks + # for the :value=>:name parameter in order to + # extract data from the form object. + # + def extract_values_from_object(name, args) + # If conditions are right, get the value from the input object. + case + when name.nil? + # This control doesn't use value look up + when args.has_key?(:value) + # Don't override given value. + when @form_object.nil? + # No structure to look up a value. + when @form_object.respond_to?(name) + # There's a data element, so get the value. + @form_object.send(name) end - end + end # extract_values_from_object ## # Generate a value for an ID tag based on the field's name. @@ -671,12 +981,21 @@ def label_for(id, value, name) # @return [String] The ID for the specified field name. # def id_for(field_name) + raise ArgumentError.new("No field name passed to id_for") if field_name.nil? if name = @form_args[:name] "#{name}_#{field_name}".downcase.gsub(/-/, '_') else "form_#{field_name}".downcase.gsub(/-/, '_') end - end + end # id_for + + ## + # Create a new hash with only the elements which have listed keys + # + def accept(hash, keys=[]) + hash.select { |k,v| keys.index(k) } + end # accept + end # Form end # BlueForm end # Helper diff --git a/lib/ramaze/version.rb b/lib/ramaze/version.rb index 4b5b716a..c8473f9c 100644 --- a/lib/ramaze/version.rb +++ b/lib/ramaze/version.rb @@ -1,3 +1,3 @@ module Ramaze - VERSION = '2012.12.08' + VERSION = '2016.05.14' end diff --git a/spec/ramaze/helper/blue_form.rb b/spec/ramaze/helper/blue_form.rb index 6f50d39d..63fb1a56 100644 --- a/spec/ramaze/helper/blue_form.rb +++ b/spec/ramaze/helper/blue_form.rb @@ -1,16 +1,18 @@ require File.expand_path('../../../../spec/helper', __FILE__) require 'ramaze/helper/blue_form' -describe BF = Ramaze::Helper::BlueForm do +describe BF = Ramaze::Helper::BlueForm do # original tests extend BF # Generate some dummy data @data = Class.new do + attr_accessor :person attr_reader :username attr_reader :password attr_reader :assigned attr_reader :assigned_hash attr_reader :message + attr_accessor :server attr_reader :servers_hash attr_reader :servers_array attr_accessor :errors @@ -30,67 +32,981 @@ def initialize end end.new + class BlueFormModel + attr_accessor :errors + def set_fields(hash, fields, opts={}) + @errors = {} + fields.each do |f| + if hash.has_key?(f) + instance_variable_set("@#{f}", hash[f]) + elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s) + instance_variable_set("@#{sf}", hash[sf]) + else + raise NoMethodError.new("undefined method `#{f.to_s}=' for #{self.inspect}") \ + if opts[:missing]!=:skip + end + end + self + end + end + + class UserX < BlueFormModel + attr_accessor :username, :password, :gender, :country, :errors + def initialize + @errors={} + end + end + # very strange comparision, sort all characters and compare, so we don't have # order issues. def assert(expected, output) left = expected.to_s.gsub(/\s+/, ' ').gsub(/>\s+<').strip right = output.to_s.gsub(/\s+/, ' ').gsub(/>\s+<').strip - left.scan(/./).sort.should == right.scan(/./).sort + lsort = left.scan(/./).sort + rsort = right.scan(/./).sort + lsort.should == rsort + end + + # ------------------------------------------------ + # Basic forms + it 'Make a basic form' do + out = form_for(@data, :method => :post) + assert(<<-FORM, out) +
+ FORM + end + + it 'Make a form with the method and action attributes specified' do + out = form_for(@data, :method => :post, :action => '/') + assert(<<-FORM, out) +
+ FORM + end + + it 'Make a form with a method, action and a name attribute' do + out = form_for(@data, :method => :post, :action => '/', :name => :spec) + assert(<<-FORM, out) +
+
+ FORM + end + + it 'Make a form with a class and an ID' do + out = form_for(@data, :class => :foo, :id => :bar) + assert(<<-FORM, out) +
+
+ FORM + end + + it 'Make a form with a fieldset and a legend' do + out = form_for(@data, :method => :get) do |f| + f.fieldset do + f.legend('The Form') + end + end + + assert(<<-FORM, out) +
+
+ The Form +
+
+ FORM + end + + # + # ------------------------------------------------ + # tag forms + it '1. Make a :text form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:text, :username, {}, {:label=>"Username"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '2. Make a :text form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:text, :username, {:value=>"mrboo"}, {:label=>"Username"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '3. Make a :text form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:text, :username, {:size=>10, :id=>"my_id"}, {:label=>"Username"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '4. Make a :password form with name and opts' do + out = form_for(nil, :method => :get) do |f| + f.tag(:password, :password, {}, {:label=>"Password"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '5. Make a :password form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:password, :password, {:value=>"super-secret-password", :class=>"password_class"}, {:label=>"Password"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '6. Make a :submit form' do + out = form_for(@data, :method => :get) do |f| + f.tag(:submit, nil, {}, {}) + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '7. Make a :submit form with args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:submit, nil, {:value=>"Send"}, {}) + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '8. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned"}) + end + + assert(<<-FORM, out) +
+

+ + bacon + steak +

+
+ FORM + end + + it '9. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>"bacon"}) + end + + assert(<<-FORM, out) +
+

+ + bacon + steak +

+
+ FORM + end + + it '10. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>"boo", :values=>["boo"]}) + end + + assert(<<-FORM, out) +
+

+ + boo +

+
+ FORM + end + + it '11. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>["boo"], :values=>["boo", "foo"]}) + end + + assert(<<-FORM, out) +
+

+ + boo + foo +

+
+ FORM + end + + it '12. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>["boo"], :values=>{"Boo"=>"boo"}}) + end + + assert(<<-FORM, out) +
+

+ + Boo +

+
+ FORM + end + + it '13. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :show_value=>false}) + end + + assert(<<-FORM, out) +
+

+ + + +

+
+ FORM + end + + it '14. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :show_label=>false}) + end + + assert(<<-FORM, out) +
+

+ bacon + steak +

+
+ FORM + end + + it '15. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned_hash, {}, {:label=>"Assigned"}) + end + + assert(<<-FORM, out) +
+

+ + Bacon + Steak +

+
+ FORM + end + + it '16. Make a :checkbox form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:checkbox, :assigned_hash, {}, {:label=>"Assigned", :checked=>"bacon"}) + end + + assert(<<-FORM, out) +
+

+ + Bacon + Steak +

+
+ FORM + end + + it '17. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + bacon + steak +

+
+ FORM + end + + it '18. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :checked=>"bacon", :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + bacon + steak +

+
+ FORM + end + + it '19. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :checked=>"boo", :values=>["boo"], :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + boo +

+
+ FORM + end + + it '20. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :show_value=>false, :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + + +

+
+ FORM + end + + it '21. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :show_label=>false, :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ bacon + steak +

+
+ FORM + end + + it '22. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned_hash, {:type=>:radio}, {:label=>"Assigned", :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + Bacon + Steak +

+
+ FORM + end + + it '23. Make a :radio form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:radio, :assigned_hash, {:type=>:radio}, {:label=>"Assigned", :checked=>"bacon", :span_class=>"radio_wrap"}) + end + + assert(<<-FORM, out) +
+

+ + Bacon + Steak +

+
+ FORM + end + + it '24. Make a :file form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:file, :file, {}, {:label=>"File"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '24. Make a :file form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:file, :file, {:id=>"awesome_file"}, {:label=>"File"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '25. Make a :hidden form with name' do + out = form_for(@data, :method => :get) do |f| + f.tag(:hidden, :username, {}, {}) + end + + assert(<<-FORM, out) +
+ +
+ FORM + end + + it '26. Make a :hidden form with name and args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:hidden, :username, {:value=>"Bob Ross"}, {}) + end + + assert(<<-FORM, out) +
+ +
+ FORM + end + + it '27. Make a :hidden form with name and args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:hidden, :username, {:id=>"test", :value=>"Bob Ross"}, {}) + end + + assert(<<-FORM, out) +
+ +
+ FORM + end + + it '28. Make a :textarea form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:textarea, :message, {}, {:label=>"Message"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '29. Make a :textarea form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:textarea, :message, {}, {:label=>"Message", :value=>"stuff"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '30. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_hash, {}, {:label=>"Server"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '31. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_hash, {}, {:label=>"Server", :selected=>:mongrel}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '32. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_array, {}, {:label=>"Server"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '33. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_array, {}, {:label=>"Server", :selected=>"Mongrel"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '34. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :people_hash, {}, {:label=>"People", :values=>{:chuck=>"Chuck", :bob=>"Bob"}}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '35. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :people_hash, {}, {:label=>"People", :selected=>:chuck, :values=>{:chuck=>"Chuck", :bob=>"Bob"}}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '36. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :people_array, {}, {:label=>"People", :values=>["Chuck", "Bob"]}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '37. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :people_array, {}, {:label=>"People", :selected=>"Chuck", :values=>["Chuck", "Bob"]}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '38. Make a :select form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '39. Make a :select form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server", :selected=>:webrick}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '40. Make a :select form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server", :selected=>[:webrick, :mongrel]}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '41. Make a :button form with args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:button, nil, {:onclick=>"fcn()", :value=>"Accept"}, {}) + end + + assert(<<-FORM, out) +
+

+
+ FORM + end + + it '42. Make a :color form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:color, :my_color, {}, {:label=>"Choose a color"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '43. Make a :email form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:email, :email, {}, {:label=>"Email"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '44. Make a :image form with args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:image, nil, {:alt=>"Submit", :src=>"http://www.w3schools.com/tags/img_submit.gif"}, {}) + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '45. Make a :number form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:number, :age, {:min=>1, :max=>120}, {:label=>"Age"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '46. Make a :range form with name, args, and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:range, :cost, {:min=>0, :max=>100}, {:label=>"Cost"}) + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM end - # ------------------------------------------------ - # Basic forms + it '47. Make a :reset form' do + out = form_for(@data, :method => :get) do |f| + f.tag(:reset, nil, {}, {}) + end - it 'Make a basic form' do - out = form_for(@data, :method => :post) assert(<<-FORM, out) -
+
+

+ +

+
FORM end - it 'Make a form with the method and action attributes specified' do - out = form_for(@data, :method => :post, :action => '/') + it '48. Make a :reset form with args' do + out = form_for(@data, :method => :get) do |f| + f.tag(:reset, nil, {:value=>"Reset"}, {}) + end + assert(<<-FORM, out) -
+
+

+ +

+
FORM end - it 'Make a form with a method, action and a name attribute' do - out = form_for(@data, :method => :post, :action => '/', :name => :spec) + it '49. Make a :url form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:url, :url, {}, {:label=>"URL"}) + end + assert(<<-FORM, out) -
-
+
+

+ + +

+
FORM end - it 'Make a form with a class and an ID' do - out = form_for(@data, :class => :foo, :id => :bar) + it '50. Make a :select form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:select, :person, {}, {:label=>"Person", :selected=>"chuck", :values=>{"chuck"=>"Chuck", "bob"=>"Bob"}}) + end + assert(<<-FORM, out) -
-
+
+

+ + +

+
FORM end - it 'Make a form with a fieldset and a legend' do + it '51. Make a :select form with name and opts' do out = form_for(@data, :method => :get) do |f| - f.fieldset do - f.legend('The Form') - end + f.tag(:select, :person, {}, {:label=>"Person", :selected=>"chuck",:values=>{"chuck"=>"Chuck", "bob"=>"Bob"}}) end assert(<<-FORM, out)
-
- The Form -
+

+ + +

+
+ FORM + end + + it '60. Make a :text/:password form with name and opts' do + params = {:username=>"gladys", :password=>"abc", :gender=>"F", :country=>"SV"} + user = UserX.new + user.set_fields(params, [:username, :password, :gender, :country], :missing=>:skip) + user.errors[:username] = "User not in system" + user.errors[:password] = "The username/password combination is not on our system" + out = form_for(user, :method => :post, :action=>"login2") do |f| + f.tag(:text, :username, {}, {:label=>"Username: "}) + f.tag(:password, :password, {}, {:label=>"Password: "}) + end + + assert(<<-FORM, out) +
+

+ + +  User not in system +

+

+ + +  The username/password combination is not on our system +

+
+ FORM + end + + it '98. Make a :text form with name and opts' do + form_error :username, 'May not be empty' + out = form_for(@data, :method => :get) do |f| + f.tag(:text, :username, {}, {:label=>"Username"}) + end + + assert(<<-FORM, out) +
+

+ + +  May not be empty +

+
+ FORM + end + + it '99. Make a :text form with name and opts' do + out = form_for(@data, :method => :get) do |f| + f.tag(:text, :username, {}, {:label=>"Username"}) + end + + assert(<<-FORM, out) +
+

+ + +  May not be empty +

FORM end + + # ------------------------------------------------ + # Clear out previous simulated errors + @form_errors = {} + # ------------------------------------------------ # Text fields - it 'Make a form with input_text(label, value)' do + it '101. Make a form with input_text(label, value)' do out = form_for(@data, :method => :get) do |f| f.input_text 'Username', :username end @@ -105,7 +1021,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_text(username, label, value)' do + it '102. Make a form with input_text(username, label, value)' do out = form_for(@data, :method => :get) do |f| f.input_text 'Username', :username, :value => 'mrboo' end @@ -120,7 +1036,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_text(label, name, size, id)' do + it '103. Make a form with input_text(label, name, size, id)' do out = form_for(@data, :method => :get) do |f| f.input_text 'Username', :username, :size => 10, :id => 'my_id' end @@ -138,7 +1054,7 @@ def assert(expected, output) # ------------------------------------------------ # Password fields - it 'Make a form with input_password(label, name)' do + it '104. Make a form with input_password(label, name)' do out = form_for(nil , :method => :get) do |f| f.input_password 'Password', :password end @@ -153,7 +1069,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_password(label, name, value, class)' do + it '105. Make a form with input_password(label, name, value, class)' do out = form_for(@data, :method => :get) do |f| f.input_password 'Password', :password, :value => 'super-secret-password', :class => 'password_class' end @@ -171,7 +1087,7 @@ def assert(expected, output) # ------------------------------------------------ # Submit buttons - it 'Make a form with input_submit()' do + it '106. Make a form with input_submit()' do out = form_for(@data, :method => :get) do |f| f.input_submit end @@ -185,7 +1101,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_submit(value)' do + it '107. Make a form with input_submit(value)' do out = form_for(@data, :method => :get) do |f| f.input_submit 'Send' end @@ -202,7 +1118,7 @@ def assert(expected, output) # ------------------------------------------------ # Checkboxes - it 'Make a form with input_checkbox(label, name)' do + it '108. Make a form with input_checkbox(label, name)' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned end @@ -218,7 +1134,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox(label, name, checked)' do + it '109. Make a form with input_checkbox(label, name, checked)' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, 'bacon' end @@ -234,7 +1150,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox(label, name, checked, values, default)' do + it '110. Make a form with input_checkbox(label, name, checked, values, default)' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, 'boo', :values => ['boo'] end @@ -249,7 +1165,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox and check multiple values using an array' do + it '111. Make a form with input_checkbox and check multiple values using an array' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, ['boo'], :values => ['boo', 'foo'] end @@ -265,7 +1181,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox and check multiple values using a hash' do + it '112. Make a form with input_checkbox and check multiple values using a hash' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, ['boo'], :values => {'Boo' => 'boo'} end @@ -280,7 +1196,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox(label, name) but hide the value of the checkbox' do + it '113. Make a form with input_checkbox(label, name) but hide the value of the checkbox' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, nil, :show_value => false end @@ -296,7 +1212,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox(label, name) but hide thelabel' do + it '114. Make a form with input_checkbox(label, name) but hide the label' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned, nil, :show_label => false end @@ -314,7 +1230,7 @@ def assert(expected, output) # ------------------------------------------------ # Checkboxes using a hash - it 'Make a form with input_checkbox(label, name) using a hash' do + it '115. Make a form with input_checkbox(label, name) using a hash' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned_hash end @@ -330,7 +1246,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_checkbox(label, name, checked) using a hash' do + it '116. Make a form with input_checkbox(label, name, checked) using a hash' do out = form_for(@data, :method => :get) do |f| f.input_checkbox 'Assigned', :assigned_hash, 'bacon' end @@ -349,7 +1265,7 @@ def assert(expected, output) # ------------------------------------------------ # Radio buttons - it 'Make a form with input_radio(label, name)' do + it '117. Make a form with input_radio(label, name)' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned end @@ -365,7 +1281,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_radio(label, name, checked)' do + it '118. Make a form with input_radio(label, name, checked)' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned, 'bacon' end @@ -381,7 +1297,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_radio(label, name, checked, values, default)' do + it '119. Make a form with input_radio(label, name, checked, values, default)' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned, 'boo', :values => ['boo'] end @@ -396,7 +1312,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_radio(label, name) but hide the value' do + it '120. Make a form with input_radio(label, name) but hide the value' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned, nil, :show_value => false end @@ -412,7 +1328,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_radio(label, name) but hide the label' do + it '121. Make a form with input_radio(label, name) but hide the label' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned, nil, :show_label => false end @@ -431,7 +1347,7 @@ def assert(expected, output) # ------------------------------------------------ # Radio buttons using a hash - it 'Make a form with input_radio(label, name) using a hash' do + it '122. Make a form with input_radio(label, name) using a hash' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned_hash end @@ -447,7 +1363,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_radio(label, name, checked) using a hash' do + it '123. Make a form with input_radio(label, name, checked) using a hash' do out = form_for(@data, :method => :get) do |f| f.input_radio 'Assigned', :assigned_hash, 'bacon' end @@ -466,7 +1382,7 @@ def assert(expected, output) # ------------------------------------------------ # File uploading - it 'Make a form with input_file(label, name)' do + it '124. Make a form with input_file(label, name)' do out = form_for(@data, :method => :get) do |f| f.input_file 'File', :file end @@ -481,7 +1397,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_file(label, name)' do + it '125. Make a form with input_file(label, name)' do out = form_for(@data, :method => :get) do |f| f.input_file 'File', :file, :id => 'awesome_file' end @@ -499,7 +1415,19 @@ def assert(expected, output) # ------------------------------------------------ # Hidden fields - it 'Make a form with input_hidden(name, value)' do + it '125. Make a form with input_hidden(name)' do + out = form_for(@data, :method => :get) do |f| + f.input_hidden :username + end + + assert(<<-FORM, out) +
+ +
+ FORM + end + + it '126. Make a form with input_hidden(name, value)' do out = form_for(@data, :method => :get) do |f| f.input_hidden :username, 'Bob Ross' end @@ -511,7 +1439,7 @@ def assert(expected, output) FORM end - it 'Make a form with input_hidden(name, value, id)' do + it '127. Make a form with input_hidden(name, value, id)' do out = form_for(@data, :method => :get) do |f| f.input_hidden :username, 'Bob Ross', :id => 'test' end @@ -526,7 +1454,7 @@ def assert(expected, output) # ------------------------------------------------ # Textarea elements - it 'Make a form with textarea(label, name)' do + it '128. Make a form with textarea(label, name)' do out = form_for(@data, :method => :get) do |f| f.textarea 'Message', :message end @@ -541,7 +1469,7 @@ def assert(expected, output) FORM end - it 'Make a form with textarea(label, name, value)' do + it '129. Make a form with textarea(label, name, value)' do out = form_for(@data, :method => :get) do |f| f.textarea 'Message', :message, :value => 'stuff' end @@ -559,7 +1487,7 @@ def assert(expected, output) # ------------------------------------------------ # Select elements - it 'Make a form with select(label, name) from a hash' do + it '130. Make a form with select(label, name) from a hash' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_hash end @@ -578,7 +1506,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name, selected) from a hash' do + it '131. Make a form with select(label, name, selected) from a hash' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_hash, :selected => :mongrel end @@ -597,7 +1525,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name) from an array' do + it '132. Make a form with select(label, name) from an array' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_array end @@ -616,7 +1544,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name, selected) from an array' do + it '133. Make a form with select(label, name, selected) from an array' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_array, :selected => 'Mongrel' end @@ -638,7 +1566,7 @@ def assert(expected, output) # ------------------------------------------------ # Select elements with custom values - it 'Make a form with select(label, name) from a hash using custom values' do + it '134. Make a form with select(label, name) from a hash using custom values' do out = form_for(@data, :method => :get) do |f| f.select 'People', :people_hash, :values => {:chuck => 'Chuck', :bob => 'Bob'} end @@ -656,7 +1584,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name, selected) from a hash using custom values' do + it '135. Make a form with select(label, name, selected) from a hash using custom values' do out = form_for(@data, :method => :get) do |f| f.select 'People', :people_hash, :values => {:chuck => 'Chuck', :bob => 'Bob'}, :selected => :chuck end @@ -674,7 +1602,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name) from an array using custom values' do + it '136. Make a form with select(label, name) from an array using custom values' do out = form_for(@data, :method => :get) do |f| f.select 'People', :people_array, :values => ['Chuck', 'Bob'] end @@ -692,7 +1620,7 @@ def assert(expected, output) FORM end - it 'Make a form with select(label, name, selected) from an array using custom values' do + it '137. Make a form with select(label, name, selected) from an array using custom values' do out = form_for(@data, :method => :get) do |f| f.select 'People', :people_array, :values => ['Chuck', 'Bob'], :selected => 'Chuck' end @@ -710,7 +1638,7 @@ def assert(expected, output) FORM end - it 'Make a form with multiple select(label, name) from a hash' do + it '138. Make a form with multiple select(label, name) from a hash' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_hash, :multiple => :multiple end @@ -729,7 +1657,7 @@ def assert(expected, output) FORM end - it 'Make a form with multiple select(label, name, selected) from a hash' do + it '139. Make a form with multiple select(label, name, selected) from a hash' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_hash, :multiple => :multiple, :selected => :webrick end @@ -748,7 +1676,7 @@ def assert(expected, output) FORM end - it 'Make a form with multiple select(label, name, selected) from a hash' do + it '140. Make a form with multiple select(label, name, selected) from a hash' do out = form_for(@data, :method => :get) do |f| f.select 'Server', :servers_hash, :multiple => :multiple, :selected => [:webrick, :mongrel] end @@ -767,10 +1695,214 @@ def assert(expected, output) FORM end + # ------------------------------------------------ + # HTML5 Extensions + + it '141. Make a form with input_button(label, value) with JavaScript call' do + out = form_for(@data, :method => :get) do |f| + f.input_button 'Accept', :onclick=>'fcn()' + end + + assert(<<-FORM, out) +
+

+
+ FORM + end + + it '142. Make a form with input_color(label, name)' do + out = form_for(@data, :method => :get) do |f| + f.input_color 'Choose a color', :my_color + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '142. Make a form with input_email(label, value)' do + out = form_for(@data, :method => :get) do |f| + f.input_email 'Email', :email + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '144. Make a form with input_image()' do + out = form_for(@data, :method => :get) do |f| + f.image "http://www.w3schools.com/tags/img_submit.gif", :alt=>"Submit" + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '145. Make a form with input_number(label, value)' do + out = form_for(@data, :method => :get) do |f| + f.input_number 'Age', :age, :min=>1, :max=>120 + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '146. Make a form with input_range(label, value)' do + out = form_for(@data, :method => :get) do |f| + f.input_range 'Cost', :cost, :min=>0, :max=>100 + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '147. Make a form with input_reset()' do + out = form_for(@data, :method => :get) do |f| + f.input_reset + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '148. Make a form with input_reset(value)' do + out = form_for(@data, :method => :get) do |f| + f.input_reset 'Reset' + end + + assert(<<-FORM, out) +
+

+ +

+
+ FORM + end + + it '149. Make a form with input_url(label, value)' do + out = form_for(@data, :method => :get) do |f| + f.input_url 'URL', :url + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + # ------------------------------------------------ + # Verify that select boxes reload from the form object + + it '150. Make a form with select(label, name, selected) take from form object' do + @data.person = "chuck" + out = form_for(@data, :method => :get) do |f| + f.select 'Person', :person, :values => {'chuck' => 'Chuck', 'bob' => 'Bob'} + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + it '151. Make a form with select(label, name, selected) take from form object' do + @data.person = "chuck" + out = form_for(@data, :method => :get) do |f| + form_error(:person, "This person has not validated his email.") + f.select 'Person', :person, :values => {'chuck' => 'Chuck', 'bob' => 'Bob'} + end + + assert(<<-FORM, out) +
+

+ + +

+
+ FORM + end + + # ------------------------------------------------ + # Code used in documentation + + it '160. Test error posting' do + params = {:username=>"gladys", :password=>"abc", :gender=>"F", :country=>"SV"} + user = UserX.new + user.set_fields(params, [:username, :password, :gender, :country], :missing=>:skip) + user.errors[:username] = "User not in system" + user.errors[:password] = "The username/password combination is not on our system" + out = form_for(user, :method=>:post, :action=>:login2) do |f| + f.text("Username: ", :username) + f.password("Password: ", :password) + end.to_html + + assert(<<-FORM, out) +
+

+ + +  User not in system +

+

+ + +  The username/password combination is not on our system +

+
+ FORM + end + # ------------------------------------------------ # Error messages - it 'Insert an error message' do + it '198. Insert an error message' do form_error :username, 'May not be empty' out = form_for(@data, :method => :get) do |f| f.input_text 'Username', :username @@ -779,17 +1911,17 @@ def assert(expected, output) assert(<<-FORM, out)

- - + + +  May not be empty

FORM end - it 'Retrieve all errors messages from the model' do + it '199. Retrieve all errors messages from the model' do @data.errors = {:username => "May not be empty"} form_errors_from_model(@data) - out = form_for(@data, :method => :get) do |f| f.input_text 'Username', :username end @@ -797,8 +1929,9 @@ def assert(expected, output) assert(<<-FORM, out)

- - + + +  May not be empty

FORM