wwidea/composable_builders

View on GitHub
lib/composable_builders/components/tagged.rb

Summary

Maintainability
A
1 hr
Test Coverage
module ComposableBuilders
  module Components
    module Tagged
      def self.included( base )
        base.extend(ClassMethods)
        base.class_eval do
          include InstanceMethods
          self.define_methods(superclass.field_helpers)
        end
      end
  
      module ClassMethods
        def define_methods(field_helpers)
          (field_helpers.map { |name| name.to_s } + %w(date_select) - %w(radio_button hidden_field apply_form_for_options! fields_for label)).each do |name|
            create_tagged_field(name)
          end

          create_tagged_field('select', 1)
          create_tagged_field('collection_select', 3)
          create_tagged_field('country_select', 1) if superclass.method_defined?(:country_select)
          create_tagged_field('calendar_date_select', 1) if superclass.method_defined?(:calendar_date_select)
        end
    
        #######
        private
        #######
    
        # create methods to wrap form methods
        # options:
        # - :tail - appended to end of content inside the div
        # - :div_options - passes options into the div tag
        # - :text - change the label text
        # - :required - marks the field as required
        # - :label_id - set the lable id
        def create_tagged_field(method_name, options_position = 0)
          define_method("#{method_name}") do |method, *args|
            options = (args[options_position] || {}).reverse_merge!(default_options)
            tail = options.delete(:tail)
            @template.content_tag(:div, options.delete(:div_options)) do
              (String.new.tap do |result|
                result << label(method, label_text(method, options.delete(:text)), id: options.delete(:label_id), class: ('required' if options.delete(:required)))
                result << super(method, *args)
                result << tail if tail
              end).html_safe
            end
          end
        end
      end

      module InstanceMethods
        
        def submit(value = 'Save Changes', options = {})
          @template.content_tag(:div, @template.submit_tag(value, options))
        end
  
        def cancel(path = {:action => 'index'})
          @template.content_tag(:div, @template.link_to_cancel(path), :class => 'cancel_link')
        end
  
        def radio_select(method, choices, opts = {})
          if opts[:field_name]
            ActiveSupport::Deprecation.warn "passing the :field_name argument is deprecated and will be removed from future releases, use :text instead.", caller
          end
          field_name = opts.delete(:text) || opts.delete(:field_name) || format_field_name(method)
          (String.new.tap { |s|
            s << @template.content_tag(:div, @template.content_tag(:label, field_name))
            s << @template.content_tag(:ul, build_radio_buttons(method, choices, opts).html_safe, :class => 'multicheck')
          }).html_safe
        end
        
        def habtm_check_boxes(*args)
          unless args[0].is_a?(String) or args[0].is_a?(Symbol)
            deprecated_habtm_check_boxes(*args)
          else
            method = args[0]
            choices = args[1]
            opts = args[2] || {}
            if opts[:field_name]
              ActiveSupport::Deprecation.warn "passing the :field_name argument is deprecated and will be removed from future releases, use :text instead.", caller
            end
            field_name = opts.delete(:text) || opts.delete(:field_name) || format_field_name(method)
            (String.new.tap { |s|
              s << @template.content_tag(:div, :class => (opts.delete(:class) || 'labeled_list')) do
                @template.content_tag(:label, field_name) +
                @template.content_tag(:ul, build_habtm_check_boxes(method, choices, opts).html_safe, :class => 'multicheck')
              end
            }).html_safe
          end
        end
      
        def deprecated_habtm_check_boxes(items, options = {})
          ActiveSupport::Deprecation.warn('Passing an array to habtm_check_boxes as the first argument is deprecated. Please use syntax consistent with _select form helpers and pass the object method name folowed by two dimensional array of choices.')
          association = options.delete(:association) || items.first.class.name.underscore.pluralize
          @template.content_tag(:div, :class => (options.delete(:class) || 'labeled_list')) do
            @template.content_tag(:label, (options.delete(:text) || association.titleize)) +
            # ensure array passed to params
            @template.hidden_field_tag(habtm_tag_name(association), nil) +
            @template.content_tag(:div) do
              @template.content_tag(:ul, :class => 'multicheck') do
                (items.inject('') do |string, item|
                  string << @template.content_tag(:li) do
                    @template.check_box_tag(habtm_tag_name(association), item.id, object.send(association).include?(item)) +
                    item.name.to_s
                  end
                end).html_safe
              end
            end
          end
        end
        
        #######
        private
        #######
        
        def label_text(method, text)
          text || method.to_s.humanize
        end
        
        def format_field_name(name)
          name = name.to_s
          name.slice!(0, name.index('.') + 1) if name.index('.')
          name.titleize
        end
        
        def build_radio_buttons(method, choices, opts)
          String.new.tap do |s|
            choices.each do |name, value|
              s << build_radio_button(method, name, value, opts[:selected])
            end
            s << build_radio_button(method, 'None') if opts[:include_blank]
          end
        end
        
        def build_habtm_check_boxes(method, choices, opts)
          String.new.tap do |s|
            choices.each do |name, value|
              s << build_habtm_check_box(method, name, value)
            end
            s << build_habtm_check_box(method, 'None') if opts[:include_blank]
          end
        end
        
        def build_radio_button(method, name, value = 0, selected = nil)
          options = selected ?  { :checked => opts[:selected] == name } : {}
          @template.content_tag(:li,
            radio_button(method, value, options) +
              @template.content_tag(:label, name, :for => "#{@object_name}_#{method}_#{value}")
          )
        end
        
        def build_habtm_check_box(method, name, value)
          @template.content_tag(:li,
            @template.hidden_field_tag(habtm_tag_name(method), nil) +
            @template.check_box_tag(habtm_tag_name(method), value, @object.send(method).try(:include?, value)) + name.to_s
          )
        end
        
        def habtm_tag_name(method)
          "#{object_name}[#{method}][]"
        end
        
        def deprecated_habtm_tag_name(association)
          "#{object_name}[#{association.singularize}_ids][]"
        end
      end
    end
  end
end