From 80b41392c7a7d5a4399f1a252193dac6abe25391 Mon Sep 17 00:00:00 2001 From: "Michael J. Welch, Ph.D" Date: Thu, 12 May 2016 01:34:23 -0700 Subject: [PATCH 1/5] Update BlueForm to HTML5 and add 'arrangements'. Created a new "tag" method which creates all the tags. The earlier methods, such as input_text, et.al., now just call "tag". Also added an "arrangement" option to allow the label-control fields to be wrapped in paragraphs (the default), or a table for nicer formatting, or no wrapping at all. --- lib/ramaze/helper/blue_form.rb | 895 ++++++++++++++++++++++----------- 1 file changed, 606 insertions(+), 289 deletions(-) diff --git a/lib/ramaze/helper/blue_form.rb b/lib/ramaze/helper/blue_form.rb index 5560be1e..0dd2b4c2 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,299 @@ 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 + + when :button, :image, :reset, :submit + args[:type] = type + args[:name] = name unless args.has_key?(:name) || name.nil? + @g.input(args) + + 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 + 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) - # 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 + # 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 - 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' - end + # Let's see if the current item is checked + if checked.include?(checkbox_value) + args[:checked] = 'checked' + else + args.delete(:checked) + end - @g.option(o_args){ o_name } + @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 - end - end - end - - ## - # 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 + 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 +979,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 From 25952e17887ca327d7fac85b480fc8260d9ff417 Mon Sep 17 00:00:00 2001 From: "Michael J. Welch, Ph.D" Date: Thu, 12 May 2016 01:46:07 -0700 Subject: [PATCH 2/5] Update ramaze/lib/ramaze/gestalt.rb to add some tags that had to be real methods in the code for the BlueForm HTML5 changes to work. --- lib/ramaze/gestalt.rb | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) 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". From 58eea236fbe3dd274a7e9d5f0222f7bd07225478 Mon Sep 17 00:00:00 2001 From: "Michael J. Welch, Ph.D" Date: Thu, 12 May 2016 01:52:29 -0700 Subject: [PATCH 3/5] Update spec/ramaze/helper/blue_form.rb to add additional tests for new BlueForm updates. Numbered the tests so I could figure out which was which. The tests below 100 are the original tests, and the ones over 100 are the new tests. If all the tests under 100 pass, the new BlueForm is completely backwards compatible. --- spec/ramaze/helper/blue_form.rb | 1277 +++++++++++++++++++++++++++++-- 1 file changed, 1205 insertions(+), 72 deletions(-) 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 From d0be3cb7c84cc9860f5b105e97d0134b3a041a7d Mon Sep 17 00:00:00 2001 From: "Michael J. Welch, Ph.D" Date: Mon, 16 May 2016 03:59:33 +0000 Subject: [PATCH 4/5] Added the input wrapper (if any) around button controls. --- lib/ramaze/helper/blue_form.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ramaze/helper/blue_form.rb b/lib/ramaze/helper/blue_form.rb index 0dd2b4c2..1014fcac 100644 --- a/lib/ramaze/helper/blue_form.rb +++ b/lib/ramaze/helper/blue_form.rb @@ -797,7 +797,9 @@ def tag(type, name, args={}, opts={}) when :button, :image, :reset, :submit args[:type] = type args[:name] = name unless args.has_key?(:name) || name.nil? - @g.input(args) + @input_wrapper.call do + @g.input(args) + end when :textarea args[:name] = name unless args.has_key?(:name) || name.nil? From db43003b212d3a897207ae35e5cc5bd5f6248034 Mon Sep 17 00:00:00 2001 From: "Michael J. Welch, Ph.D" Date: Mon, 16 May 2016 04:00:16 +0000 Subject: [PATCH 5/5] Updated the version number to 2016.05.14. --- lib/ramaze/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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