class TbCore::FormBuilder < ActionView::Helpers::FormBuilder ############### # Basic Helpers # # Use the following methods as the basic building blocks for your forms # # Build a form group # def tb_form_group(content=nil, options={}) content_tag :div, options.merge(class: 'form-group') do if block_given? yield else content end end end # Build a label # def tb_label(attribute, options={}) if options[:label_text] != nil text = options[:label_text] else text = @object.class.human_attribute_name(attribute) end label(attribute, text, class: 'col-sm-2 control-label') end # Builds an input field with error message # def tb_input_field_tag(attribute, input_type=nil, options={}) content_tag(:div, class: 'col-sm-10') do if block_given? concat(yield(attribute)) else options[:class] ||= 'form-control' options[:placeholder] ||= @object.class.human_attribute_name(attribute) concat send(input_type, attribute, objectify_options(options)) end error_message = @object.errors[attribute].first if options[:help_text] concat content_tag(:p, @template.raw(options[:help_text]), class: 'help-block') end if error_message concat content_tag(:p, error_message, class: 'form-error form-error-inline') end end end # Builds a text field # def tb_text_field_tag(attribute, options={}) tb_input_field_tag(attribute, :text_field, options) end # Builds a text area # def tb_text_area_tag(attribute, options={}) tb_input_field_tag(attribute, :text_area, options) end # Builds a password field # def tb_password_field_tag(attribute, options={}) tb_input_field_tag(attribute, :password_field, options) end # Builds a number field # def tb_number_field_tag(attribute, options={}) tb_input_field_tag(attribute, :number_field, options) end # Builds a check box # def tb_check_box_tag(attribute, options={}) tb_input_field_tag(attribute, :check_box, options) end # Builds a select tag # def tb_select_tag(attribute, option_tags, options={}, html_options={}) tb_input_field_tag(attribute) do select(attribute, option_tags, objectify_options(options), html_options.merge(class: 'form-control')) end end # Builds a date select tag # def tb_date_select_tag(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field_tag(attribute) do date_select(attribute, objectify_options(options), html_options.merge(class: 'form-control date-select')) end end # Builds a date select tag # def tb_datetime_select_tag(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field_tag(attribute) do datetime_select(attribute, objectify_options(options), html_options.merge(class: 'form-control datetime-select')) end end # Builds a time select tag # def tb_time_select_tag(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field_tag(attribute) do time_select(attribute, objectify_options(options), html_options.merge(class: 'form-control datetime-select')) end end # Builds a row of save/cancel buttons # def tb_save_buttons(model_name, cancel_path, delete_path=nil) content_tag :div, class: 'form-group' do content_tag :div, class: 'col-sm-offset-2 col-sm-10' do concat submit "Save #{model_name}", class: 'btn btn-primary', data: { disable_with: "Saving #{model_name}...", enable_with: 'Saved!' } concat ' ' concat @template.link_to 'Cancel', cancel_path, class: 'btn btn-default', data: {dismiss: :modal} if delete_path != nil concat ' ' concat @template.link_to 'Delete', delete_path, class: 'btn btn-danger', data: {confirm: "This action can't be undone. Would you like to delete the #{model_name.downcase}?"}, method: :delete end end end end ################## # Advanced Helpers # # These helpers are designed to output an entire form group with child elements # ie, container div + label + input + error message # def tb_sub_title(text, options={}) content_tag :div, options.merge(class: 'form-group') do content_tag :div, class: 'col-sm-offset-2 col-sm-10' do content_tag :h4, text, class: 'form-sub-title' end end end # Builds a form group, label, and input tag all in one # def tb_input_field(attribute, input_type=nil, options={}) tb_form_group() do concat tb_label(attribute, options) if block_given? concat( tb_input_field_tag(attribute) do yield end ) else if input_type.nil? input_type = determine_input_type_from_attribute(attribute) end concat tb_input_field_tag(attribute, input_type, options) end end end # Builds a text field group # def tb_text_field(attribute, options={}) options[:maxlength] ||= get_limit_for_column(attribute) tb_input_field(attribute, :text_field, options) end # Builds a email field group # def tb_email_field(attribute, options={}) tb_input_field(attribute, :email_field, options) end # Builds a telephone field group # def tb_phone_field(attribute, options={}) tb_input_field(attribute, :phone_field, options) end # Builds a text area group # def tb_text_area(attribute, options={}) tb_input_field(attribute, :text_area, options) end # Builds a password field group # def tb_password_field(attribute, options={}) tb_input_field(attribute, :password_field, options) end # Builds a number field group # def tb_number_field(attribute, options={}) tb_input_field(attribute, :number_field, options) end # Builds a check box # def tb_check_box(attribute, options={}) tb_input_field(attribute) do check_box(attribute, options) end end # Builds a file field group # def tb_file_field(attribute, options={}) tb_input_field(attribute, nil, options) do file_field(attribute) end end # Builds a select group # def tb_select(attribute, option_tags, options={}, html_options={}) tb_input_field(attribute) do select(attribute, option_tags, objectify_options(options), html_options.merge(class: 'form-control')) end end # Builds a date select tag # def tb_date_select(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field(attribute) do date_select(attribute, objectify_options(options), html_options.merge(class: 'form-control date-select')) end end # Builds a date select tag # def tb_datetime_select(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field(attribute) do datetime_select(attribute, objectify_options(options), html_options.merge(class: 'form-control datetime-select')) end end # Builds a time select tag # def tb_time_select(attribute, options={}, html_options={}) options[:with_css_classes] = true tb_input_field(attribute) do time_select(attribute, objectify_options(options), html_options.merge(class: 'form-control datetime-select')) end end # Builds a time zone select group # def tb_time_zone_select(attribute, priority_zones, options={}, html_options={}) tb_input_field(attribute) do time_zone_select(attribute, priority_zones, objectify_options(options), html_options.merge(class: 'form-control')) end end # Return a picker for a new or existing user # # * attribute: The spud user column name. Default = spud_user_id. # * users: Optional query object representing the list of users to display. Default = all users. # * selected: Desired id to select. Will try to look up the value currently on the record if blank. # * default_text: Text to show for blank option. Default = 'Select User' # def tb_user_select(attribute = :spud_user_id, users: SpudUser.ordered, selected: nil, default_text: 'Select User') selected = @object[attribute] if selected.nil? return content_tag :div, class: 'form-group' do concat label attribute, class: 'control-label col-sm-2' concat content_tag(:div, class: 'col-sm-10'){ concat select( attribute, @template.options_from_collection_for_select(users, :id, :full_name_with_email, selected), {include_blank: default_text}, class: 'form-control tb-user-select' ) concat @template.link_to 'Edit User', @template.edit_admin_user_path(':id'), class: 'btn btn-default tb-user-select-btn tb-user-select-edit' concat @template.link_to 'New User', @template.new_admin_user_path, class: 'btn btn-default tb-user-select-btn tb-user-select-add' } end end private def concat(*args) @template.concat(*args) end def content_tag(*args) if block_given? @template.content_tag(*args) do yield end else @template.content_tag(*args) end end def determine_input_type_from_attribute(attribute) # TODO: Intelligently return the correct input for the given attribute return :text_field end def get_limit_for_column(attribute) if @object.class.respond_to?(:columns) col = @object.class.columns.find{ |c| c.name == attribute.to_s } if col.present? && col.sql_type.match(/^varchar/) return col.limit end end return nil end end