module KingForm module Builder # Base Form Helper Class overrides most of rails build in form / field methods. # This class is used in conjunction with haml and makes your templates ultra clean. # # To further specify the resulting html for form fields and their wrappers, # subclass KingForm::Builder::Base. # # Subclasses must define the following methods: # # ==== def section # Definition of a section inside a form. A section is a wrapper around fields # which belong together. The topmost element should be(most of the time) a fieldset # followed by a legend and the openeing definition list. # fieldset-> legend -> div -> .... # fieldset-> legend -> dl -> ... # See child class Labeled and DefinitionList for examples. # # ==== def tag_wrapper # Wrapping/display of field descriptions(labels) and input tags # => wrapped with div. actually no wrapping(see above): # fieldset-> div -> label -> input # => wrapped with dt / dd # fieldset-> dl -> dd -> dt -> input # # # ==== def bundle # handle fields which are displayed toghether inside a wrapper class Base < ActionView::Helpers::FormBuilder include KingForm::Builder::FormFields include KingForm::Builder::FormFieldsOverrides attr_accessor :no_wrap def initialize(object_name, object, template, options, proc) # Store builder configuration data (only used by "render_associated_form") @config = options.delete(:config) || {} super(object_name, object, template, options, proc) end # Create a section(fieldset) within a form # A section is a group of related object information with name/value pairs, # like all dates of an object or the users name fields(last/first/title/nick). def section(title = nil, options = {}, &block) #must be overwritten in inerit classes end # Show multiple inputs as bundle def bundle(title = nil, options = {}, &block) #must be redefined in inerit class end # For using with nested forms with associated records => contact => addresses # Another Builder instance will be created. Make sure it's also a DefinitionsListsFormBuilder # and configuration data is available for the new created instance def render_nested_form(associated, opts = {}) opts[:fields_for] = { :builder => KingForm::Builder::DefinitionList, :config => @config } super(associated, opts) end # wraps a list of action links/buttons in a td od div # those wrappers can then be formated with css td.actions # also see #ListHelper # # ===Example haml # = f.actions do # = link_to my_actions # #
my actions
# my actions # def actions(options = {}, &block) options[:class] ||= 'actions' if @config[:table] @template.haml_tag :td, @template.capture_haml(&block), options else @template.haml_tag :div, @template.capture_haml(&block), options end end #build a table def table(title, options = {}, &block) # Capture the block (with analyzing the header titles) @config[:table] = true @config[:column_header] = [] @config[:row_number] = 0 content = @template.capture_haml(&block) # Now build the whole table tag result = @template.capture_haml do @template.haml_tag :table, options.reverse_merge({ :summary => title }) do @template.haml_tag :thead do @template.haml_tag :tr do @config[:column_header].each do |c| c[:options][:class] ||= '' if c == @config[:column_header].first c[:options][:class] << ' first' elsif c == @config[:column_header].last c[:options][:class] << ' last' end @template.haml_tag :th, c[:title], c[:options] end end end @template.haml_tag :tbody, content end end @config[:table] = false return result end # Build a single table row, only needed to be be able to render the table # headers(th) def table_row(&block) @config[:row_number] += 1 @template.concat " #{@template.capture(&block)}" end private # returns the current object def current_object # check for fields made with attribute_fu if @object_name.to_s.match(/\[\w+_attributes\]/) #field was constructed via attribute_fu: user[address_attributes][atLE1aPLKr3j9zabTJhScS] @object else # Instance-Variable of the templates @template.instance_variable_get("@#{@object_name}") end end # returns the class of the current object def current_class current_object.class end # returns the value of an attribute belonging to the current object def current_value(fieldname) if current_object.is_a?(Hash) current_object[fieldname] else current_object.send(fieldname) rescue nil end end # Shortcut for using "content_tag", which exists in the context of the template def content_tag(*args) @template.content_tag(*args) end # Translate acts_as_enum dropdown field values either with I18n # A key must be lokated in the language file under: # "activerecord.attributes.client.enum.sending_methods.fax" # "activerecord.attributes.client.enum.sending_methods.email" # ==== Parameter # fieldname:: The fieldname in the model which holds enum values from acts_as_enum plugin # === Returns # 'value'}>:: def enum_values(fieldname) # Check if there is a const in the class defined by acts_as_enum return unless current_class.const_defined?(fieldname.to_s.upcase) # Get Array with the values from this constant values = current_class.const_get(fieldname.to_s.upcase) # values are symbols as defined by "acts_as_enum" if values && values.first.is_a?(Symbol) values_with_translated_keys = {} values.each do |value| key = translate_namespaced_enum_key(current_class, fieldname, value) values_with_translated_keys[key] = value.to_s end return values_with_translated_keys else #values are not symbols (probably not coming from acts_as_enum) =>return them unchanged return values end end # translation_key for fieldname # replaces current_class.human_attribute_name("enum.#{fieldname.to_s}.#{value.to_s}") # as `human_attribute_name` changed the way how "."'s are interpreted in 3.2.x (now as namespaces) def translate_namespaced_enum_key(klass, field, value) defaults = klass.lookup_ancestors.map do |_klass| :"#{klass.i18n_scope}.attributes.#{_klass.model_name.i18n_key}.enum.#{field.to_s}.#{value.to_s}" end I18n.translate(default: defaults) end # add titles to Input-Tag and embed/wrap in dt/dd # options: Hash with following keys # :dt => options for dt # :dd => options for dd def tag_wrapper(fieldname_or_title, tags, options = {}) #overwrite in inherit class !!! end # Build a fields title/label with translation # takes the class and fieldname (like GetText ActiveRecord-Parser ) # ==== Parameter # fieldname_or_title:: A string is directly returned. # A Symbol is beeing looked up in I18n translation inside the models attribute namespace: # => class.human_attribute_name(fieldname_or_title.to_s) def build_title(fieldname_or_title) if fieldname_or_title.is_a?(Symbol) #i18n namespace under activerecord.attributes.model.attr_name current_class.human_attribute_name(fieldname_or_title.to_s) if current_class.respond_to?(:human_attribute_name) else fieldname_or_title end end # Build span-tag with an info text after a field # ==== Parameter # fieldname_or_text:: static text value or a fieldname as symbol. # If a symbol is given the translated text is taken from I18n translation file def info_tag(fieldname_or_text) case fieldname_or_text when String #just use the plain string value = fieldname_or_text when Symbol # lookup the the field in i18n under activerecord.attributes.class.fieldname_info key = "#{current_class.name.underscore}.#{fieldname_or_text.to_s}_info" trans = I18n.translate("#{key}_html", :default => I18n.translate(key, :default => '', :scope => [:activerecord, :attributes]), :scope => [:activerecord, :attributes]) value = trans.blank? ? nil : trans else raise ArgumentError end value ? content_tag(:div, value.html_safe, :class => 'info').html_safe : '' end # Create the id of a field # ==== Parameter # name::The name of the id def build_id(name) if current_object.blank? name else "#{@object_name}_#{name}" end end end #Class Base end#Module Builder end#Module KingForm