Parent

Console::Formtastic::BootstrapFormBuilder

Public Class Methods

new(object_name, object, template, options, proc) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 7
def initialize(object_name, object, template, options, proc)
  options[:html] ||= {}
  class_names = options[:html][:class] ? options[:html][:class].split(" ") : []

  class_names << 'form-inline' if options[:simple]
  options[:html][:class] = class_names.join(" ")

  super
end

Public Instance Methods

boolean_input(method, options) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 334
def boolean_input(method, options)
  html_options  = options.delete(:input_html) || {}
  checked_value = options.delete(:checked_value) || '1'
  unchecked_value = options.delete(:unchecked_value) || '0'
  checked = @object && ActionView::Helpers::InstanceTag.check_box_checked?(@object.send(:"#{method}"), checked_value)

  html_options[:id] = html_options[:id] || generate_html_id(method, "")
  input_html = template.check_box_tag(
    "#{@object_name}[#{method}]",
    checked_value,
    checked,
    html_options
  )

  label_options = options_for_label(options)
  label_options[:for] ||= html_options[:id]
  (label_options[:class] ||= []) << 'checkbox'

  input_html << localized_string(method, label_options[:label], :label) || humanized_attribute_name(method)
  label_options.delete :label

  safe_input_html = ::Formtastic::Util.html_safe(input_html)

  return safe_input_html if input_inline?

  template.content_tag(:div, label(method, safe_input_html, label_options), {:class => 'controls'}) << template.hidden_field_tag((html_options[:name] || "#{@object_name}[#{method}]"), unchecked_value, :id => nil, :disabled => html_options[:disabled])
end
buttons(*args) click to toggle source

set the default css class

# File lib/console/formtastic/bootstrap_form_builder.rb, line 18
def buttons(*args)
  options = args.extract_options!
  options[:class] ||= @options[:simple] ? 'btn-toolbar' : 'form-actions'
  super *(args << options)
end
check_boxes_input(method, options) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 362
def check_boxes_input(method, options)
  collection = find_collection_for_column(method, options)
  html_options = options.delete(:input_html) || {}

  input_name      = generate_association_input_name(method)
  hidden_fields   = options.delete(:hidden_fields)
  value_as_class  = options.delete(:value_as_class)
  unchecked_value = options.delete(:unchecked_value) || ''
  html_options    = { :name => "#{@object_name}[#{input_name}][]" }.merge(html_options)
  input_ids       = []

  selected_values = find_selected_values_for_column(method, options)
  disabled_option_is_present = options.key?(:disabled)
  disabled_values = [*options[:disabled]] if disabled_option_is_present

  li_options = value_as_class ? { :class => [method.to_s.singularize, 'default'].join('_') } : {}

  list_item_content = collection.map do |c|
    label = c.is_a?(Array) ? c.first : c
    value = c.is_a?(Array) ? c.last : c
    input_id = generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
    input_ids << input_id

    html_options[:checked] = selected_values.include?(value)
    html_options[:disabled] = (disabled_values.include?(value) || options[:disabled] == true) if disabled_option_is_present
    html_options[:id] = input_id

    li_content = template.content_tag(:label,
      ::Formtastic::Util.html_safe("#{create_check_boxes(input_name, html_options, value, unchecked_value, hidden_fields)} #{escape_html_entities(label)}"),
      :for => input_id, :class => 'checkbox',
    )

    li_options = value_as_class ? { :class => [method.to_s.singularize, value.to_s.downcase].join('_') } : {}
    template.content_tag(:li, ::Formtastic::Util.html_safe(li_content), li_options)
  end

  list_html = parts(method, options) do
    template.content_tag(:ul, ::Formtastic::Util.html_safe(list_item_content.join), :class => 'unstyled')
  end

  content = label(method, :class => 'control-label', :for => html_options[:id])
  content << create_hidden_field_for_check_boxes(input_name, value_as_class) unless hidden_fields
  content << template.content_tag(:div, ::Formtastic::Util.html_safe(list_html), {:class => 'controls'})
end
commit_button(*args) click to toggle source

remove the button wrapper

# File lib/console/formtastic/bootstrap_form_builder.rb, line 408
def commit_button(*args)
  options = args.extract_options!
  text = options.delete(:label) || args.shift

  if @object && (@object.respond_to?(:persisted?) || @object.respond_to?(:new_record?))
    if @object.respond_to?(:persisted?) # ActiveModel
      key = @object.persisted? ? :update : :create
    else # Rails 2
      key = @object.new_record? ? :create : :update
    end

    # Deal with some complications with ActiveRecord::Base.human_name and two name models (eg UserPost)
    # ActiveRecord::Base.human_name falls back to ActiveRecord::Base.name.humanize ("Userpost")
    # if there's no i18n, which is pretty crappy.  In this circumstance we want to detect this
    # fall back (human_name == name.humanize) and do our own thing name.underscore.humanize ("User Post")
    if @object.class.model_name.respond_to?(:human)
      object_name = @object.class.model_name.human
    else
      object_human_name = @object.class.human_name                # default is UserPost => "Userpost", but i18n may do better ("User post")
      crappy_human_name = @object.class.name.humanize             # UserPost => "Userpost"
      decent_human_name = @object.class.name.underscore.humanize  # UserPost => "User post"
      object_name = (object_human_name == crappy_human_name) ? decent_human_name : object_human_name
    end
  else
    key = :submit
    object_name = @object_name.to_s.send(label_str_method)
  end

  text = (localized_string(key, text, :action, :model => object_name) ||
          ::Formtastic::I18n.t(key, :model => object_name)) unless text.is_a?(::String)

  button_html = options.delete(:button_html) || {}
  button_html.merge!(:class => [button_html[:class] || 'btn btn-primary', key].compact.join(' '))

  #remove need for wrapper
  #wrapper_html_class = ['btn-primary'] #changed # TODO: Add class reflecting on form action.
  #wrapper_html = options.delete(:wrapper_html) || {}
  #wrapper_html[:class] = (wrapper_html_class << wrapper_html[:class]).flatten.compact.join(' ')

  accesskey = (options.delete(:accesskey) || default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
  button_html = button_html.merge(:accesskey => accesskey) if accesskey
  submit(text, button_html) # no wrapper
end
inline_fields_and_wrapping(*args, &block) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 174
def inline_fields_and_wrapping(*args, &block)
  contents = args.last.is_a?(::Hash) ? '' : args.pop.flatten
  html_options = args.extract_options!

  html_options.delete(:inline)
  html_class = ['control-group']
  html_class << 'control-group-important' if html_options.delete(:important)

  label = template.content_tag(:label, ::Formtastic::Util.html_safe(html_options.dup.delete(:name).to_s) << required_or_optional_string(html_options.delete(:required)), { :class => 'control-label' }) if html_options[:name]

  # Generate form elements
  if block_given?
    contents = if template.respond_to?(:is_haml?) && template.is_haml?
      template.capture_haml(&block)
    else
      template.capture(&block)
    end
  end

  # Ruby 1.9: String#to_s behavior changed, need to make an explicit join.
  #contents = contents.join if contents.respond_to?(:join)
  unless html_options[:without_errors]
    contents << send(:"error_#{inline_errors}", [*@input_inline_errors], {})
    html_class << 'error' unless @input_inline_errors.empty?
  end

  @input_inline_hints.each do |hint|
    contents << template.content_tag(:p, hint, :class => default_hint_class)
  end

  template.content_tag(:div, ::Formtastic::Util.html_safe(label || '') << template.content_tag(:div, ::Formtastic::Util.html_safe(contents), {:class => 'controls'}), { :class => html_class.join(' ') })
end
input(method, options = {}) click to toggle source

change from li to div.control-group, move hints/errors into the input block

# File lib/console/formtastic/bootstrap_form_builder.rb, line 212
def input(method, options = {})
  options = options.dup # Allow options to be shared without being tainted by Formtastic

  options[:required] = method_required?(method) unless options.key?(:required)
  options[:as]     ||= default_input_type(method, options)

  if (field = options[:autocomplete])
    if (section = @autocomplete_section)
      field = "#{section} #{field}"
    end
    options[:input_html] ||= {}
    options[:input_html][:autocomplete] = field
  end

  html_class = [ 
    options[:as], 
    options[:required] ? :required : :optional, 
    'control-group',
  ] #changed
  html_class << 'control-group-important' if options[:important]

  wrapper_html = options.delete(:wrapper_html) || {}
  if has_errors?(method, options)
    html_class << 'error'

    wrapper_html[:"data-server-error"] = "server-error"
    
    options[:input_html] ||= {}
    options[:input_html][:class] ||= ""
    options[:input_html][:class] << " error"
  end
  wrapper_html[:id]  ||= generate_html_id(method)
  wrapper_html[:class] = (html_class << wrapper_html[:class]).flatten.compact.join(' ')

  if options[:input_html] && options[:input_html][:id]
    options[:label_html] ||= {}
    options[:label_html][:for] ||= options[:input_html][:id]
  end

  # moved hint/error output inside basic_input_helper
  safe_html_output = ::Formtastic::Util.html_safe(inline_input_for(method, options))
  return safe_html_output if input_inline?
  template.content_tag(:div, safe_html_output, wrapper_html) #changed to move to basic_input_helper
end
input_inline?() click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 207
def input_inline?
  @input_inline
end
inputs(*args, &block) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 133
def inputs(*args, &block)
  title = field_set_title_from_args(*args)
  html_options = args.extract_options!
  html_options[:class] ||= "inputs"
  html_options[:name] = title

  if html_options[:autocomplete]
    @old_autocomplete_section = @autocomplete_section
    @autocomplete_section = html_options[:autocomplete]
  end

  if html_options[:for] # Nested form
    inputs_for_nested_attributes(*(args << html_options), &block)
  elsif html_options[:inline]
    @input_inline = true
    @input_inline_errors = []
    @input_inline_hints = []
    fieldset = inline_fields_and_wrapping(*(args << html_options), &block)
    @input_inline = false
    @label = nil
    fieldset
  elsif block_given?
    field_set_and_list_wrapping(*(args << html_options), &block)
  else
    if @object && args.empty?
      args  = association_columns(:belongs_to)
      args += content_columns
      args -= RESERVED_COLUMNS
      args.compact!
    end
    legend = args.shift if args.first.is_a?(::String)
    contents = args.collect { |method| input(method.to_sym) }
    args.unshift(legend) if legend.present?

    field_set_and_list_wrapping(*((args << html_options) << contents))
  end

ensure
  @autocomplete_section = @old_autocomplete_section
end
loading(*args) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 24
def loading(*args)
  image = template.instance_variable_get(:@loader_image) || template.image_path('loader.gif')
  template.content_tag(:img, nil, :alt => 'Working...', 'data-loading' => 'true', :class => 'icon-loading', :style => 'display: none', :src => image)
end
parts(method, options, &block) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 257
def parts(method, options, &block)
  input_parts = (custom_inline_order[options[:as]] || inline_order).dup
  input_parts = input_parts - [:errors, :hints] if options[:as] == :hidden
  input_parts.map do |type|
    (:input == type) ? yield : send(:"inline_#{type}_for", method, options)
  end.compact.join("\n")
end
select_input(method, options) click to toggle source

wrap select in a control

# File lib/console/formtastic/bootstrap_form_builder.rb, line 285
def select_input(method, options)
  html_options = options.delete(:input_html) || {}
  html_options[:multiple] = html_options[:multiple] || options.delete(:multiple)
  html_options.delete(:multiple) if html_options[:multiple].nil?

  reflection = reflection_for(method)
  if reflection && [ :has_many, :has_and_belongs_to_many ].include?(reflection.macro)
    html_options[:multiple] = true if html_options[:multiple].nil?
    html_options[:size]     ||= 5
    options[:include_blank] ||= false
  end
  options = set_include_blank(options)
  input_name = generate_association_input_name(method)
  html_options[:id] ||= generate_html_id(input_name, "")

  select_html = if options[:group_by]
    # The grouped_options_select is a bit counter intuitive and not optimised (mostly due to ActiveRecord).
    # The formtastic user however shouldn't notice this too much.
    raw_collection = find_raw_collection_for_column(method, options.reverse_merge(:find_options => { :include => options[:group_by] }))
    label, value = detect_label_and_value_method!(raw_collection, options)
    group_collection = raw_collection.map { |option| option.send(options[:group_by]) }.uniq
    group_label_method = options[:group_label_method] || detect_label_method(group_collection)
    group_collection = group_collection.sort_by { |group_item| group_item.send(group_label_method) }
    group_association = options[:group_association] || detect_group_association(method, options[:group_by])

    # Here comes the monster with 8 arguments
    grouped_collection_select(input_name, group_collection,
                                   group_association, group_label_method,
                                   value, label,
                                   strip_formtastic_options(options), html_options)
  else
    collection = find_collection_for_column(method, options)

    select(input_name, collection, strip_formtastic_options(options), html_options)
  end

  label_options = options_for_label(options).merge(:input_name => input_name)
  label_options[:for] ||= html_options[:id]

  select_html = parts(method, options) do
    select_html
  end

  safe_select_html = ::Formtastic::Util.html_safe(select_html)

  return safe_select_html if input_inline?
  label(method, label_options) << template.content_tag(:div, safe_select_html, {:class => 'controls'})
end
semantic_errors(*args) click to toggle source
# File lib/console/formtastic/bootstrap_form_builder.rb, line 56
def semantic_errors(*args)
  html_options = args.extract_options!
  html_options[:class] ||= 'alert alert-error unstyled errors'
  except = Array(html_options.delete(:except))
  # Skip the base here because we will add it later if desired
  except << :base
  desired_keys = args.present? ? args : (@object.errors.keys - except)

  # Loop through all of the aliased attributes and merge them
  unless (aliases = html_options.delete(:alias)).nil?
    aliases.each do |master,_alias|
      if @object.errors.include?(_alias)
        @object.errors[master] |= @object.errors.delete(_alias)
      end
    end
  end

  # Make sure the merged attributes are a flat array
  @object.errors.keys.each do |key|
    @object.errors.set(key, @object.errors[key].flatten.compact.uniq)
  end

  full_errors = desired_keys.inject([]) do |array, method|
    attribute = localized_string(method, method.to_sym, :label) || humanized_attribute_name(method)
    @object.errors[method.to_sym].each do |error|
      if error.present?
        error = [attribute, error].join(" ") unless error[0,1] == error[0,1].upcase
        array << error
      end
    end
    array
  end

  full_errors << @object.errors[:base] unless html_options.delete(:not) == :base or args.present?
  full_errors.flatten!
  full_errors.compact!
  full_errors.uniq!

  return nil if full_errors.blank?
  #html_options[:class] ||= "errors"
  template.content_tag(:ul, html_options) do
    ::Formtastic::Util.html_safe(full_errors.map { |error| template.content_tag(:li, error) }.join)
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.