padrino-helpers 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/padrino-helpers.rb +4 -1
- data/lib/padrino-helpers/asset_tag_helpers.rb +17 -14
- data/lib/padrino-helpers/breadcrumb_helpers.rb +6 -6
- data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +119 -163
- data/lib/padrino-helpers/form_builder/deprecated_builder_methods.rb +92 -0
- data/lib/padrino-helpers/form_helpers.rb +66 -347
- data/lib/padrino-helpers/form_helpers/errors.rb +138 -0
- data/lib/padrino-helpers/form_helpers/options.rb +97 -0
- data/lib/padrino-helpers/form_helpers/security.rb +70 -0
- data/lib/padrino-helpers/output_helpers.rb +1 -1
- data/lib/padrino-helpers/output_helpers/abstract_handler.rb +1 -1
- data/lib/padrino-helpers/render_helpers.rb +10 -9
- data/lib/padrino-helpers/tag_helpers.rb +2 -1
- data/lib/padrino/rendering.rb +378 -0
- data/lib/padrino/rendering/extensions/erubis.rb +74 -0
- data/lib/padrino/rendering/extensions/haml.rb +29 -0
- data/lib/padrino/rendering/extensions/slim.rb +21 -0
- data/padrino-helpers.gemspec +2 -1
- data/test/fixtures/apps/.components +6 -0
- data/test/fixtures/apps/.gitignore +7 -0
- data/test/fixtures/apps/render.rb +25 -0
- data/test/fixtures/apps/views/article/comment/show.slim +1 -0
- data/test/fixtures/apps/views/blog/post.erb +1 -0
- data/test/fixtures/apps/views/layouts/specific.erb +1 -0
- data/test/fixtures/apps/views/test/post.erb +1 -0
- data/test/fixtures/layouts/layout.erb +1 -0
- data/test/fixtures/markup_app/app.rb +0 -1
- data/test/fixtures/render_app/app.rb +25 -1
- data/test/fixtures/render_app/views/_unsafe.html.builder +2 -0
- data/test/fixtures/render_app/views/_unsafe_object.html.builder +2 -0
- data/test/fixtures/render_app/views/ruby_block_capture_erb.erb +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_haml.haml +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_slim.slim +1 -0
- data/test/helper.rb +65 -1
- data/test/test_asset_tag_helpers.rb +83 -79
- data/test/test_breadcrumb_helpers.rb +20 -20
- data/test/test_form_builder.rb +196 -196
- data/test/test_form_helpers.rb +163 -163
- data/test/test_format_helpers.rb +65 -65
- data/test/test_locale.rb +1 -1
- data/test/test_number_helpers.rb +10 -11
- data/test/test_output_helpers.rb +28 -28
- data/test/test_render_helpers.rb +89 -35
- data/test/test_rendering.rb +683 -0
- data/test/test_rendering_extensions.rb +14 -0
- data/test/test_tag_helpers.rb +23 -23
- metadata +57 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9de9c68240b6a030c87053b1f781ef7152ef5bfc
         | 
| 4 | 
            +
              data.tar.gz: a9a5d042cd4ed7d6dd52d9977b4421c0a40389e2
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: f0d72f6b0c05eaae7fb28d4fd7c85d7d76a9e2e7a7ef719f42040b0148cdbfb19ccdd3f790ef592328ec341edaf15acf74cda7b6e24b21aa4ce25beaa2af44fa
         | 
| 7 | 
            +
              data.tar.gz: 97eb607b9c2caf7c9242c39afa18ceac5f63e7306d46c0e01d3041e93bf3008fef4e0a7b7f03bfc5ba9624b3cb6a7bd2fc9520e63cc9a85396af7d52c621e347
         | 
    
        data/lib/padrino-helpers.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            require 'padrino- | 
| 1 | 
            +
            require 'padrino-support'
         | 
| 2 2 | 
             
            require 'i18n'
         | 
| 3 3 | 
             
            require 'enumerator'
         | 
| 4 4 | 
             
            require 'active_support/time_with_zone'               # next extension depends on this
         | 
| @@ -6,6 +6,8 @@ require 'active_support/core_ext/string/conversions'  # to_date | |
| 6 6 | 
             
            require 'active_support/option_merger'                # with_options
         | 
| 7 7 | 
             
            require 'active_support/core_ext/object/with_options' # with_options
         | 
| 8 8 | 
             
            require 'active_support/inflector'                    # humanize
         | 
| 9 | 
            +
            require 'active_support/core_ext/hash/except'         # Hash#except
         | 
| 10 | 
            +
            require 'padrino/rendering'
         | 
| 9 11 |  | 
| 10 12 | 
             
            FileSet.glob_require('padrino-helpers/**/*.rb', __FILE__)
         | 
| 11 13 | 
             
            I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-helpers/locale/*.yml"]
         | 
| @@ -41,6 +43,7 @@ module Padrino | |
| 41 43 | 
             
                  #   end
         | 
| 42 44 | 
             
                  #
         | 
| 43 45 | 
             
                  def registered(app)
         | 
| 46 | 
            +
                    app.register Padrino::Rendering
         | 
| 44 47 | 
             
                    app.set :default_builder, 'StandardFormBuilder'
         | 
| 45 48 | 
             
                    app.helpers Padrino::Helpers::OutputHelpers
         | 
| 46 49 | 
             
                    app.helpers Padrino::Helpers::TagHelpers
         | 
| @@ -32,11 +32,11 @@ module Padrino | |
| 32 32 | 
             
                  def flash_tag(*args)
         | 
| 33 33 | 
             
                    options = args.extract_options!
         | 
| 34 34 | 
             
                    bootstrap = options.delete(:bootstrap) if options[:bootstrap]
         | 
| 35 | 
            -
                    args.inject( | 
| 36 | 
            -
                      flash_text = flash[kind]
         | 
| 35 | 
            +
                    args.inject(ActiveSupport::SafeBuffer.new) do |html,kind|
         | 
| 36 | 
            +
                      flash_text = ActiveSupport::SafeBuffer.new << flash[kind]
         | 
| 37 37 | 
             
                      next html if flash_text.blank?
         | 
| 38 | 
            -
                      flash_text <<  | 
| 39 | 
            -
                      html <<  | 
| 38 | 
            +
                      flash_text << content_tag(:button, '×'.html_safe, {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
         | 
| 39 | 
            +
                      html << content_tag(:div, flash_text, { :class => kind }.update(options))
         | 
| 40 40 | 
             
                    end
         | 
| 41 41 | 
             
                  end
         | 
| 42 42 |  | 
| @@ -230,11 +230,13 @@ module Padrino | |
| 230 230 | 
             
                  #
         | 
| 231 231 | 
             
                  # @api public.
         | 
| 232 232 | 
             
                  def stylesheet_link_tag(*sources)
         | 
| 233 | 
            -
                    options =  | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 237 | 
            -
                     | 
| 233 | 
            +
                    options = {
         | 
| 234 | 
            +
                      :rel => 'stylesheet',
         | 
| 235 | 
            +
                      :type => 'text/css'
         | 
| 236 | 
            +
                    }.update(sources.extract_options!.symbolize_keys)
         | 
| 237 | 
            +
                    sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
         | 
| 238 | 
            +
                      all << tag(:link, { :href => asset_path(:css, source) }.update(options))
         | 
| 239 | 
            +
                    end
         | 
| 238 240 | 
             
                  end
         | 
| 239 241 |  | 
| 240 242 | 
             
                  ##
         | 
| @@ -252,11 +254,12 @@ module Padrino | |
| 252 254 | 
             
                  #   javascript_include_tag 'application', :extjs
         | 
| 253 255 | 
             
                  #
         | 
| 254 256 | 
             
                  def javascript_include_tag(*sources)
         | 
| 255 | 
            -
                    options =  | 
| 256 | 
            -
             | 
| 257 | 
            -
                    sources. | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 257 | 
            +
                    options = {
         | 
| 258 | 
            +
                      :type => 'text/javascript'
         | 
| 259 | 
            +
                    }.update(sources.extract_options!.symbolize_keys)
         | 
| 260 | 
            +
                    sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
         | 
| 261 | 
            +
                      all << content_tag(:script, nil, { :src => asset_path(:js, source) }.update(options))
         | 
| 262 | 
            +
                    end
         | 
| 260 263 | 
             
                  end
         | 
| 261 264 |  | 
| 262 265 | 
             
                  ##
         | 
| @@ -143,7 +143,7 @@ module Padrino | |
| 143 143 | 
             
                  #  # </ul>
         | 
| 144 144 | 
             
                  #
         | 
| 145 145 | 
             
                  def breadcrumbs(breadcrumbs, bootstrap = false, active = "active", options = {})
         | 
| 146 | 
            -
                    content =  | 
| 146 | 
            +
                    content = ActiveSupport::SafeBuffer.new
         | 
| 147 147 | 
             
                    breadcrumbs.items[0..-2].each do |item|
         | 
| 148 148 | 
             
                      content << render_item(item, bootstrap)
         | 
| 149 149 | 
             
                    end
         | 
| @@ -156,8 +156,8 @@ module Padrino | |
| 156 156 | 
             
                    classes[1] << active if active
         | 
| 157 157 | 
             
                    options[:class], last_options[:class] = classes.map { |class_name| class_name * " " }
         | 
| 158 158 |  | 
| 159 | 
            -
                    content <<  | 
| 160 | 
            -
                     | 
| 159 | 
            +
                    content << content_tag(:li, last, last_options)
         | 
| 160 | 
            +
                    content_tag(:ul, content, options)
         | 
| 161 161 | 
             
                  end
         | 
| 162 162 |  | 
| 163 163 | 
             
                  private
         | 
| @@ -173,10 +173,10 @@ module Padrino | |
| 173 173 | 
             
                  # @return [String] List item with breadcrumb
         | 
| 174 174 | 
             
                  #
         | 
| 175 175 | 
             
                  def render_item(item, bootstrap)
         | 
| 176 | 
            -
                    content =  | 
| 176 | 
            +
                    content = ActiveSupport::SafeBuffer.new
         | 
| 177 177 | 
             
                    content << link_to(item[:caption], item[:url])
         | 
| 178 | 
            -
                    content <<  | 
| 179 | 
            -
                     | 
| 178 | 
            +
                    content << content_tag(:span, "/", :class => "divider") if bootstrap
         | 
| 179 | 
            +
                    content_tag(:li, content, item[:options])
         | 
| 180 180 | 
             
                  end
         | 
| 181 181 | 
             
                end
         | 
| 182 182 | 
             
              end
         | 
| @@ -1,129 +1,119 @@ | |
| 1 | 
            +
            require 'padrino-helpers/form_builder/deprecated_builder_methods'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Padrino
         | 
| 2 4 | 
             
              module Helpers
         | 
| 3 5 | 
             
                module FormBuilder
         | 
| 6 | 
            +
                  # Base class for Padrino Form Builder
         | 
| 4 7 | 
             
                  class AbstractFormBuilder
         | 
| 5 8 | 
             
                    attr_accessor :template, :object, :multipart
         | 
| 9 | 
            +
                    attr_reader :namespace, :is_nested, :parent_form, :nested_index, :attributes_name, :model_name
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    include DeprecatedBuilderMethods
         | 
| 6 12 |  | 
| 7 13 | 
             
                    def initialize(template, object, options={})
         | 
| 8 14 | 
             
                      @template = template
         | 
| 9 | 
            -
                       | 
| 10 | 
            -
                      @ | 
| 11 | 
            -
                       | 
| 12 | 
            -
                       | 
| 15 | 
            +
                      fail "FormBuilder template must be initialized" unless template
         | 
| 16 | 
            +
                      @object = object.kind_of?(Symbol) ? build_object(object) : object
         | 
| 17 | 
            +
                      fail "FormBuilder object must be present. If there's no object, use a symbol instead (i.e. :user)" unless object
         | 
| 18 | 
            +
                      @options = options
         | 
| 19 | 
            +
                      @namespace = options[:namespace]
         | 
| 20 | 
            +
                      @model_name = options[:as] || @object.class.to_s.underscore.gsub(/\//, '_')
         | 
| 21 | 
            +
                      nested = options[:nested]
         | 
| 22 | 
            +
                      if @is_nested = nested && (nested_parent = nested[:parent]) && nested_parent.respond_to?(:object)
         | 
| 23 | 
            +
                        @parent_form = nested_parent
         | 
| 24 | 
            +
                        @nested_index = nested[:index]
         | 
| 25 | 
            +
                        @attributes_name = "#{nested[:association]}_attributes"
         | 
| 26 | 
            +
                      end
         | 
| 13 27 | 
             
                    end
         | 
| 14 28 |  | 
| 15 29 | 
             
                    def error_messages(*params)
         | 
| 16 | 
            -
                       | 
| 17 | 
            -
                      @template.error_messages_for(*params)
         | 
| 30 | 
            +
                      @template.error_messages_for object, *params
         | 
| 18 31 | 
             
                    end
         | 
| 19 32 |  | 
| 20 33 | 
             
                    def error_message_on(field, options={})
         | 
| 21 | 
            -
                      @template.error_message_on | 
| 34 | 
            +
                      @template.error_message_on object, field, options
         | 
| 22 35 | 
             
                    end
         | 
| 23 36 |  | 
| 24 37 | 
             
                    def label(field, options={}, &block)
         | 
| 25 | 
            -
                      options | 
| 26 | 
            -
                      @template.label_tag(field_id(field), options, &block)
         | 
| 38 | 
            +
                      options[:caption] ||= I18n.t("#{model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models) + ': '
         | 
| 39 | 
            +
                      @template.label_tag(field_id(field), default_options(field, options), &block)
         | 
| 27 40 | 
             
                    end
         | 
| 28 41 |  | 
| 29 42 | 
             
                    def hidden_field(field, options={})
         | 
| 30 | 
            -
                       | 
| 31 | 
            -
                      @template.hidden_field_tag field_name(field), options
         | 
| 43 | 
            +
                      @template.hidden_field_tag field_name(field), default_options(field, options)
         | 
| 32 44 | 
             
                    end
         | 
| 33 45 |  | 
| 34 46 | 
             
                    def text_field(field, options={})
         | 
| 35 | 
            -
                       | 
| 36 | 
            -
                      @template.text_field_tag field_name(field), options
         | 
| 47 | 
            +
                      @template.text_field_tag field_name(field), default_options(field, options)
         | 
| 37 48 | 
             
                    end
         | 
| 38 49 |  | 
| 39 50 | 
             
                    def number_field(field, options={})
         | 
| 40 | 
            -
                       | 
| 41 | 
            -
                      @template.number_field_tag field_name(field), options
         | 
| 51 | 
            +
                      @template.number_field_tag field_name(field), default_options(field, options)
         | 
| 42 52 | 
             
                    end
         | 
| 43 53 |  | 
| 44 54 | 
             
                    def telephone_field(field, options={})
         | 
| 45 | 
            -
                       | 
| 46 | 
            -
                      @template.telephone_field_tag field_name(field), options
         | 
| 55 | 
            +
                      @template.telephone_field_tag field_name(field), default_options(field, options)
         | 
| 47 56 | 
             
                    end
         | 
| 48 57 | 
             
                    alias_method :phone_field, :telephone_field
         | 
| 49 58 |  | 
| 50 59 | 
             
                    def email_field(field, options={})
         | 
| 51 | 
            -
                       | 
| 52 | 
            -
                      @template.email_field_tag field_name(field), options
         | 
| 60 | 
            +
                      @template.email_field_tag field_name(field), default_options(field, options)
         | 
| 53 61 | 
             
                    end
         | 
| 54 62 |  | 
| 55 63 | 
             
                    def search_field(field, options={})
         | 
| 56 | 
            -
                       | 
| 57 | 
            -
                      @template.search_field_tag field_name(field), options
         | 
| 64 | 
            +
                      @template.search_field_tag field_name(field), default_options(field, options)
         | 
| 58 65 | 
             
                    end
         | 
| 59 66 |  | 
| 60 67 | 
             
                    def url_field(field, options={})
         | 
| 61 | 
            -
                       | 
| 62 | 
            -
                      @template.url_field_tag field_name(field), options
         | 
| 68 | 
            +
                      @template.url_field_tag field_name(field), default_options(field, options)
         | 
| 63 69 | 
             
                    end
         | 
| 64 70 |  | 
| 65 71 | 
             
                    def text_area(field, options={})
         | 
| 66 | 
            -
                       | 
| 67 | 
            -
                      @template.text_area_tag field_name(field), options
         | 
| 72 | 
            +
                      @template.text_area_tag field_name(field), default_options(field, options)
         | 
| 68 73 | 
             
                    end
         | 
| 69 74 |  | 
| 70 75 | 
             
                    def password_field(field, options={})
         | 
| 71 | 
            -
                       | 
| 72 | 
            -
                      @template.password_field_tag field_name(field), options
         | 
| 76 | 
            +
                      @template.password_field_tag field_name(field), default_options(field, options)
         | 
| 73 77 | 
             
                    end
         | 
| 74 78 |  | 
| 75 79 | 
             
                    def select(field, options={})
         | 
| 76 | 
            -
                       | 
| 77 | 
            -
                      options.merge!(:class => field_error(field, options))
         | 
| 78 | 
            -
                      @template.select_tag field_name(field), options
         | 
| 80 | 
            +
                      @template.select_tag field_name(field), default_options(field, options)
         | 
| 79 81 | 
             
                    end
         | 
| 80 82 |  | 
| 81 83 | 
             
                    def check_box_group(field, options={})
         | 
| 82 | 
            -
                       | 
| 83 | 
            -
             | 
| 84 | 
            -
                        fields = options[:fields] || [:name, :id]
         | 
| 85 | 
            -
                        selected_values = selected_values.map{ |v| (v.respond_to?(fields[0]) ? v.send(fields[1]) : v).to_s }
         | 
| 86 | 
            -
                      end
         | 
| 87 | 
            -
                      labeled_group( field, options ) do |variant|
         | 
| 88 | 
            -
                        @template.check_box_tag( field_name(field)+'[]', :value => variant[1], :id => variant[2], :checked => selected_values.include?(variant[1]) )
         | 
| 84 | 
            +
                      labeled_group(field, options) do |attributes|
         | 
| 85 | 
            +
                        @template.check_box_tag(field_name(field)+'[]', attributes)
         | 
| 89 86 | 
             
                      end
         | 
| 90 87 | 
             
                    end
         | 
| 91 88 |  | 
| 92 89 | 
             
                    def radio_button_group(field, options={})
         | 
| 93 | 
            -
                       | 
| 94 | 
            -
             | 
| 95 | 
            -
                      selected_value = selected_value.send(fields[1])  if selected_value.respond_to?(fields[0])
         | 
| 96 | 
            -
                      labeled_group( field, options ) do |variant|
         | 
| 97 | 
            -
                        @template.radio_button_tag( field_name(field), :value => variant[1], :id => variant[2], :checked => variant[1] == selected_value.to_s )
         | 
| 90 | 
            +
                      labeled_group(field, options) do |attributes|
         | 
| 91 | 
            +
                        @template.radio_button_tag(field_name(field), attributes)
         | 
| 98 92 | 
             
                      end
         | 
| 99 93 | 
             
                    end
         | 
| 100 94 |  | 
| 101 95 | 
             
                    def check_box(field, options={})
         | 
| 102 | 
            -
                       | 
| 103 | 
            -
                       | 
| 104 | 
            -
                       | 
| 105 | 
            -
                       | 
| 106 | 
            -
                      html << @template. | 
| 107 | 
            -
                      html << @template.check_box_tag(field_name(field), options)
         | 
| 96 | 
            +
                      options = default_options(field, options, :value => '1')
         | 
| 97 | 
            +
                      options[:checked] = true if is_checked?(field, options)
         | 
| 98 | 
            +
                      name = field_name(field)
         | 
| 99 | 
            +
                      html = @template.hidden_field_tag(name, :value => options.delete(:uncheck_value) || '0')
         | 
| 100 | 
            +
                      html << @template.check_box_tag(name, options)
         | 
| 108 101 | 
             
                    end
         | 
| 109 102 |  | 
| 110 103 | 
             
                    def radio_button(field, options={})
         | 
| 111 | 
            -
                      options | 
| 112 | 
            -
                      options | 
| 104 | 
            +
                      options = default_options(field, options)
         | 
| 105 | 
            +
                      options[:checked] = true if is_checked?(field, options)
         | 
| 106 | 
            +
                      options[:id] = field_id(field, options[:value])
         | 
| 113 107 | 
             
                      @template.radio_button_tag field_name(field), options
         | 
| 114 108 | 
             
                    end
         | 
| 115 109 |  | 
| 116 110 | 
             
                    def file_field(field, options={})
         | 
| 117 111 | 
             
                      self.multipart = true
         | 
| 118 | 
            -
                       | 
| 119 | 
            -
                      options.merge!(:class => field_error(field, options))
         | 
| 120 | 
            -
                      @template.file_field_tag field_name(field), options
         | 
| 112 | 
            +
                      @template.file_field_tag field_name(field), default_options(field, options).except(:value)
         | 
| 121 113 | 
             
                    end
         | 
| 122 114 |  | 
| 123 115 | 
             
                    def submit(*args)
         | 
| 124 | 
            -
                       | 
| 125 | 
            -
                      caption = args.length >= 1 ? args.shift : "Submit"
         | 
| 126 | 
            -
                      @template.submit_tag caption, options
         | 
| 116 | 
            +
                      @template.submit_tag *args
         | 
| 127 117 | 
             
                    end
         | 
| 128 118 |  | 
| 129 119 | 
             
                    def image_submit(source, options={})
         | 
| @@ -136,24 +126,16 @@ module Padrino | |
| 136 126 | 
             
                    # f.fields_for :addresses, address
         | 
| 137 127 | 
             
                    # f.fields_for :addresses, @addresses
         | 
| 138 128 | 
             
                    # f.fields_for :addresses, address, index: i
         | 
| 139 | 
            -
                    def fields_for(child_association,  | 
| 129 | 
            +
                    def fields_for(child_association, collection=nil, options={}, &block)
         | 
| 140 130 | 
             
                      default_collection = self.object.send(child_association)
         | 
| 141 | 
            -
             | 
| 131 | 
            +
                      collection ||= default_collection
         | 
| 142 132 | 
             
                      include_index = default_collection.respond_to?(:each)
         | 
| 143 | 
            -
                      custom_index = options.has_key?(:index)
         | 
| 144 133 |  | 
| 145 134 | 
             
                      nested_options = { :parent => self, :association => child_association }
         | 
| 146 | 
            -
                       | 
| 147 | 
            -
             | 
| 148 | 
            -
                         | 
| 149 | 
            -
             | 
| 150 | 
            -
                        elsif include_index
         | 
| 151 | 
            -
                          nested_options[:index] = index
         | 
| 152 | 
            -
                        else
         | 
| 153 | 
            -
                          nested_options[:index] = nil
         | 
| 154 | 
            -
                        end
         | 
| 155 | 
            -
                        @template.fields_for(child_instance,  { :nested => nested_options }, &block)
         | 
| 156 | 
            -
                      end.join("\n").html_safe
         | 
| 135 | 
            +
                      Array(collection).each_with_index.inject(ActiveSupport::SafeBuffer.new) do |all,(child_instance,index)|
         | 
| 136 | 
            +
                        nested_options[:index] = options[:index] || (include_index ? index : nil)
         | 
| 137 | 
            +
                        all << @template.fields_for(child_instance,  { :nested => nested_options }, &block) << "\n"
         | 
| 138 | 
            +
                      end
         | 
| 157 139 | 
             
                    end
         | 
| 158 140 |  | 
| 159 141 | 
             
                    def csrf_token_field
         | 
| @@ -161,43 +143,21 @@ module Padrino | |
| 161 143 | 
             
                    end
         | 
| 162 144 |  | 
| 163 145 | 
             
                    protected
         | 
| 146 | 
            +
             | 
| 164 147 | 
             
                    # Returns the known field types for a Formbuilder.
         | 
| 165 148 | 
             
                    def self.field_types
         | 
| 166 149 | 
             
                      [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
         | 
| 167 150 | 
             
                    end
         | 
| 168 151 |  | 
| 169 | 
            -
                    ##
         | 
| 170 | 
            -
                    # Returns true if the value matches the value in the field.
         | 
| 171 | 
            -
                    # field_has_value?(:gender, 'male')
         | 
| 172 | 
            -
                    def values_matches_field?(field, value)
         | 
| 173 | 
            -
                      value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
         | 
| 174 | 
            -
                    end
         | 
| 175 | 
            -
             | 
| 176 | 
            -
                    ##
         | 
| 177 | 
            -
                    # Add a :invalid css class to the field if it contain an error.
         | 
| 178 | 
            -
                    #
         | 
| 179 | 
            -
                    def field_error(field, options)
         | 
| 180 | 
            -
                      error = @object.errors[field] rescue nil
         | 
| 181 | 
            -
                      error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
         | 
| 182 | 
            -
                    end
         | 
| 183 | 
            -
             | 
| 184 | 
            -
                    ##
         | 
| 185 | 
            -
                    # Returns the human name of the field. Look that use builtin I18n.
         | 
| 186 | 
            -
                    #
         | 
| 187 | 
            -
                    def field_human_name(field)
         | 
| 188 | 
            -
                      I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
         | 
| 189 | 
            -
                    end
         | 
| 190 | 
            -
             | 
| 191 152 | 
             
                    ##
         | 
| 192 153 | 
             
                    # Returns the name for the given field.
         | 
| 193 154 | 
             
                    # field_name(:username) => "user[username]"
         | 
| 194 155 | 
             
                    # field_name(:number) => "user[telephone_attributes][number]"
         | 
| 195 156 | 
             
                    # field_name(:street) => "user[addresses_attributes][0][street]"
         | 
| 196 157 | 
             
                    def field_name(field=nil)
         | 
| 197 | 
            -
                      result =  | 
| 198 | 
            -
                      result << field_name_fragment if nested_form?
         | 
| 158 | 
            +
                      result = field_name_fragment
         | 
| 199 159 | 
             
                      result << "[#{field}]" unless field.blank?
         | 
| 200 | 
            -
                      result | 
| 160 | 
            +
                      result
         | 
| 201 161 | 
             
                    end
         | 
| 202 162 |  | 
| 203 163 | 
             
                    ##
         | 
| @@ -207,118 +167,114 @@ module Padrino | |
| 207 167 | 
             
                    # field_name(:number) => "user_telephone_attributes_number"
         | 
| 208 168 | 
             
                    # field_name(:street) => "user_addresses_attributes_0_street"
         | 
| 209 169 | 
             
                    def field_id(field=nil, value=nil)
         | 
| 210 | 
            -
                      result =  | 
| 211 | 
            -
                      result <<  | 
| 212 | 
            -
                      result << field_result
         | 
| 213 | 
            -
                      result << field_id_fragment if nested_form?
         | 
| 170 | 
            +
                      result = (namespace && !is_nested) ? "#{namespace}_" : ''
         | 
| 171 | 
            +
                      result << field_id_fragment
         | 
| 214 172 | 
             
                      result << "_#{field}" unless field.blank?
         | 
| 215 173 | 
             
                      result << "_#{value}" unless value.blank?
         | 
| 216 | 
            -
                      result | 
| 174 | 
            +
                      result
         | 
| 217 175 | 
             
                    end
         | 
| 218 176 |  | 
| 219 177 | 
             
                    ##
         | 
| 220 178 | 
             
                    # Returns the child object if it exists.
         | 
| 221 179 | 
             
                    #
         | 
| 222 180 | 
             
                    def nested_object_id
         | 
| 223 | 
            -
                       | 
| 224 | 
            -
                    end
         | 
| 225 | 
            -
             | 
| 226 | 
            -
                    ##
         | 
| 227 | 
            -
                    # Returns true if this form object is nested in a parent form.
         | 
| 228 | 
            -
                    #
         | 
| 229 | 
            -
                    def nested_form?
         | 
| 230 | 
            -
                      @options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
         | 
| 181 | 
            +
                      is_nested && object.respond_to?(:new_record?) && !object.new_record? && object.id
         | 
| 231 182 | 
             
                    end
         | 
| 232 183 |  | 
| 233 184 | 
             
                    ##
         | 
| 234 185 | 
             
                    # Returns the value for the object's field.
         | 
| 235 186 | 
             
                    #
         | 
| 236 187 | 
             
                    def field_value(field)
         | 
| 237 | 
            -
                      @object | 
| 188 | 
            +
                      @object.respond_to?(field) ? @object.send(field) : ''
         | 
| 238 189 | 
             
                    end
         | 
| 239 190 |  | 
| 240 191 | 
             
                    ##
         | 
| 241 | 
            -
                    # Returns a  | 
| 192 | 
            +
                    # Returns a record from template instance or create a record of specified class.
         | 
| 242 193 | 
             
                    #
         | 
| 243 | 
            -
                    def build_object( | 
| 244 | 
            -
                       | 
| 194 | 
            +
                    def build_object(symbol)
         | 
| 195 | 
            +
                      @template.instance_variable_get("@#{symbol}") || symbol.to_s.camelize.constantize.new
         | 
| 245 196 | 
             
                    end
         | 
| 246 197 |  | 
| 247 198 | 
             
                    ##
         | 
| 248 | 
            -
                    #  | 
| 199 | 
            +
                    # Builds a group of labels for radios or checkboxes.
         | 
| 249 200 | 
             
                    #
         | 
| 250 | 
            -
                    def  | 
| 251 | 
            -
                       | 
| 252 | 
            -
                       | 
| 201 | 
            +
                    def labeled_group(field, options={})
         | 
| 202 | 
            +
                      options = { :id => field_id(field), :selected => field_value(field) }.update(options)
         | 
| 203 | 
            +
                      options.update(error_class(field)){ |_,*values| values.compact.join(' ') }
         | 
| 204 | 
            +
                      selected_values = resolve_checked_values(field, options)
         | 
| 205 | 
            +
                      variants_for_group(options).inject(ActiveSupport::SafeBuffer.new) do |html, (caption,value)|
         | 
| 206 | 
            +
                        variant_id = "#{options[:id]}_#{value}"
         | 
| 207 | 
            +
                        attributes = { :value => value, :id => variant_id, :checked => selected_values.include?(value) }
         | 
| 208 | 
            +
                        caption = yield(attributes) << ' ' << caption
         | 
| 209 | 
            +
                        html << @template.label_tag("#{field_name(field)}[]", :for => variant_id, :caption => caption)
         | 
| 210 | 
            +
                      end
         | 
| 253 211 | 
             
                    end
         | 
| 254 212 |  | 
| 255 | 
            -
                     | 
| 256 | 
            -
                    # Returns the class type for the given object.
         | 
| 257 | 
            -
                    #
         | 
| 258 | 
            -
                    def object_class(explicit_object)
         | 
| 259 | 
            -
                      explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
         | 
| 260 | 
            -
                    end
         | 
| 213 | 
            +
                    private
         | 
| 261 214 |  | 
| 262 | 
            -
                     | 
| 263 | 
            -
             | 
| 264 | 
            -
                    #
         | 
| 265 | 
            -
                    def root_form?
         | 
| 266 | 
            -
                      !nested_form?
         | 
| 215 | 
            +
                    def is_checked?(field, options)
         | 
| 216 | 
            +
                      !options.has_key?(:checked) && [options[:value].to_s, 'true'].include?(field_value(field).to_s)
         | 
| 267 217 | 
             
                    end
         | 
| 268 218 |  | 
| 269 | 
            -
                     | 
| 270 | 
            -
             | 
| 271 | 
            -
             | 
| 272 | 
            -
             | 
| 273 | 
            -
             | 
| 274 | 
            -
                      options.merge!(:class => field_error(field, options))
         | 
| 275 | 
            -
                      variants = case
         | 
| 276 | 
            -
                      when options[:options]
         | 
| 277 | 
            -
                        options[:options].map{ |caption, value| [caption.to_s, (value||caption).to_s] }
         | 
| 278 | 
            -
                      when options[:collection]
         | 
| 279 | 
            -
                        fields = options[:fields] || [:name, :id]
         | 
| 280 | 
            -
                        options[:collection].map{ |variant| [variant.send(fields.first).to_s, variant.send(fields.last).to_s] }
         | 
| 219 | 
            +
                    def variants_for_group(options)
         | 
| 220 | 
            +
                      if variants = options[:options]
         | 
| 221 | 
            +
                        variants.map{ |caption, value| [caption.to_s, (value||caption).to_s] }
         | 
| 222 | 
            +
                      elsif collection = options[:collection]
         | 
| 223 | 
            +
                        collection.map{ |variant| field_values(variant, options) }
         | 
| 281 224 | 
             
                      else
         | 
| 282 225 | 
             
                        []
         | 
| 283 226 | 
             
                      end
         | 
| 284 | 
            -
             | 
| 285 | 
            -
             | 
| 286 | 
            -
             | 
| 287 | 
            -
             | 
| 227 | 
            +
                    end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                    def resolve_checked_values(field, options)
         | 
| 230 | 
            +
                      selected_values = Array(options[:selected] || field_value(field))
         | 
| 231 | 
            +
                      if options[:collection]
         | 
| 232 | 
            +
                        _, id_method = *field_methods(options)
         | 
| 233 | 
            +
                        selected_values.map do |value|
         | 
| 234 | 
            +
                          (value.respond_to?(id_method) ? value.send(id_method) : value).to_s
         | 
| 235 | 
            +
                        end
         | 
| 236 | 
            +
                      else
         | 
| 237 | 
            +
                        selected_values
         | 
| 288 238 | 
             
                      end
         | 
| 289 239 | 
             
                    end
         | 
| 290 240 |  | 
| 291 | 
            -
                     | 
| 241 | 
            +
                    def field_methods(options)
         | 
| 242 | 
            +
                      options[:fields] || [:name, :id]
         | 
| 243 | 
            +
                    end
         | 
| 292 244 |  | 
| 293 | 
            -
                    def  | 
| 294 | 
            -
                       | 
| 295 | 
            -
                      result << object_model_name if root_form?
         | 
| 296 | 
            -
                      result
         | 
| 245 | 
            +
                    def field_values(object, options)
         | 
| 246 | 
            +
                      field_methods(options).map{ |field| object.send(field).to_s }
         | 
| 297 247 | 
             
                    end
         | 
| 298 248 |  | 
| 299 249 | 
             
                    def field_name_fragment
         | 
| 300 | 
            -
                       | 
| 301 | 
            -
             | 
| 302 | 
            -
             | 
| 250 | 
            +
                      if is_nested
         | 
| 251 | 
            +
                        fragment = parent_form.field_name.dup << "[#{attributes_name}"
         | 
| 252 | 
            +
                        fragment << "][#{nested_index}" if nested_index
         | 
| 253 | 
            +
                        fragment << "]"
         | 
| 254 | 
            +
                      else
         | 
| 255 | 
            +
                        "#{model_name}"
         | 
| 256 | 
            +
                      end
         | 
| 303 257 | 
             
                    end
         | 
| 304 258 |  | 
| 305 259 | 
             
                    def field_id_fragment
         | 
| 306 | 
            -
                       | 
| 307 | 
            -
             | 
| 308 | 
            -
             | 
| 260 | 
            +
                      if is_nested
         | 
| 261 | 
            +
                        fragment = parent_form.field_id.dup << "_#{attributes_name}"
         | 
| 262 | 
            +
                        fragment << "_#{nested_index}" if nested_index
         | 
| 263 | 
            +
                        fragment
         | 
| 264 | 
            +
                      else
         | 
| 265 | 
            +
                        "#{model_name}"
         | 
| 266 | 
            +
                      end
         | 
| 309 267 | 
             
                    end
         | 
| 310 268 |  | 
| 311 | 
            -
                    def  | 
| 312 | 
            -
                       | 
| 313 | 
            -
             | 
| 314 | 
            -
                        :nested_index => @options[:nested][:index],
         | 
| 315 | 
            -
                        :attributes_name => "#{@options[:nested][:association]}_attributes"
         | 
| 316 | 
            -
                      }
         | 
| 269 | 
            +
                    def error_class(field)
         | 
| 270 | 
            +
                      error = @object.errors[field] if @object.respond_to?(:errors)
         | 
| 271 | 
            +
                      error.blank? ? {} : { :class => 'invalid' }
         | 
| 317 272 | 
             
                    end
         | 
| 318 273 |  | 
| 319 | 
            -
                    def  | 
| 320 | 
            -
                       | 
| 321 | 
            -
             | 
| 274 | 
            +
                    def default_options(field, options, defaults={})
         | 
| 275 | 
            +
                      { :value => field_value(field),
         | 
| 276 | 
            +
                        :id => field_id(field)
         | 
| 277 | 
            +
                      }.update(defaults).update(options).update(error_class(field)){ |_,*values| values.compact.join(' ') }
         | 
| 322 278 | 
             
                    end
         | 
| 323 279 | 
             
                  end
         | 
| 324 280 | 
             
                end
         |