root/lib/plus_forms.rb

Download in other formats: Raw | Text
Revisions
Dimitrij Denissenko
Dimitrij Denissenko
Jan 24 2009 * 11:51
(over 1 year ago)

Revision b1794537d634e7833190d162a0351bc60046c8fc

Initial public import

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
module PlusForms
  
  module Helper
    [:form_for, :fields_for, :form_remote_for, :remote_form_for].each do |meth|
      src = <<-end_src
        def plus_#{meth}(object_name, *args, &proc)
          options = args.last.is_a?(Hash) ? args.pop : {}
          options.update(:builder => FormBuilder)
          options[:html] ||= {}
          options[:html][:class] ||= ''
          options[:html][:class] = (['plus_form'] + options[:html][:class].split(' ')).join(' ')
          #{meth}(object_name, *(args << options), &proc)
        end
      end_src
      module_eval src, __FILE__, __LINE__
    end
  end

  class FormBuilder < ActionView::Helpers::FormBuilder #:nodoc:  
    cattr_accessor :font_styles
    self.font_styles = {
      :info => :h2,
      :section => :h3      
    }
    
    def fields_for(object_name, *args, &proc)
      @template.plus_fields_for(object_name, *args, &proc)
    end

    def fieldset(*args, &block)
      content = @template.capture(&block)      
      @template.concat(fieldset_tag(content, *args))
    end
    
    def fieldset_tag(text, *args)
      options = args.last.is_a?(Hash) ? args.pop : {}
      instruction = options.delete(:instruct)
      
      options[:class] = args.flatten.map(&:to_s).join(' ')      
      if instruction
        text = instruct(instruction) + text
      end
      @template.content_tag(:fieldset, text, options)
    end
          
    def info(title, &block)      
      content = @template.content_tag font_styles[:info], title
      if block_given?
        content += @template.capture(&block) 
        @template.concat(fieldset_tag(content, :info))
      else
        fieldset_tag content, :info
      end
    end

    def section(title, &block)      
      content = @template.content_tag font_styles[:section], title
      if block_given?
        content += @template.capture(&block) 
        @template.concat(fieldset_tag(content, :section))
      else
        fieldset_tag content, :section
      end
    end


    def label(method, text = nil, options = {})
      if text && options.delete(:required)
        text += ' <span class="required">*</span>'
      end
      super(method, text, options)
    end

    def explain(method, text, options = {})
      label method, text, options.merge(:class => 'explain')
    end

    def label_tag(text, options = {})
      label(nil, text, options)
    end

    def instruct(text, options = {})
      options[:tag] ||= :p
      @template.content_tag options[:tag], text, :class => 'instruct'
    end


    def radio_buttons(method, choices, options = {})
      return '' if choices.blank?

      content = choices.map do |label, value|
        @template.radio_button(object_name, method, value) + ' ' + 
          click_choice(label, :for => [object_name, method, value])
      end.join(options[:inline] ? ' ' : '<br/>')      
      wrap_field(options[:wrap], content, options[:wrap_options])
    end
    
    def check_boxes(method, choices, options = {})
      return '' if choices.blank?
      
      columns = options[:cols] || 1
      per_col = options[:per_col] || (choices.size.to_f / columns.to_f).ceil
      
      choices.in_groups_of(per_col).map do |group|
        name = "#{object_name}[#{method}][]"
        content = group.compact.map do |label, value|
          element_id = "#{object_name}_#{method}_#{value}"
          checked = object.send(method).include?(value) rescue false
          @template.check_box_tag(name, value, checked, :id => element_id) + 
            click_choice(label, :for => [object_name, method, value])
        end.join(options[:inline] ? ' ' : '<br/>')
        content += @template.hidden_field_tag name, nil, :id => "#{object_name}_#{method}_hidden"
        wrap_field(options[:wrap], content, options[:wrap_options])
      end.join("\n")
    end

    def collection_check_boxes(method, collection, id_method = :id, name_method = :name, options = {})
      choices = collection.map do |i| 
        [@template.send(:h, i.send(name_method)), i.send(id_method)]
      end
      check_boxes method, choices, options
    end

    def click_choice(content, options = {})
      options[:for] = options[:for].map(&:to_s).join('_') if options[:for].is_a?(Array)
      options[:class] ||= 'choice'
      label_tag content, options
    end

    ['text_field', 'text_area', 'password_field', 'hidden_field', 'file_field', 'date_select'].each do |selector|
      src = <<-end_src
        def #{selector}(method, options = {})
          text = options.delete(:explain)
          wrap = options.delete(:wrap)
          wopt = options.delete(:wrap_options)
          content = super(method, options) + 
            (text.blank? ? '' : explain(method, text))
          wrap_field(wrap, content, wopt)
        end
      end_src
      class_eval src, __FILE__, __LINE__
    end

    def select(method, choices, options = {}, html_options = {})
      text = options.delete(:explain)
      wrap = options.delete(:wrap)
      wopt = options.delete(:wrap_options)
      content = super(method, choices, options, html_options) + 
        (text.blank? ? '' : explain(method, text))
      wrap_field(wrap, content, wopt)
    end

    def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
      text = options.delete(:explain)
      wrap = options.delete(:wrap)
      wopt = options.delete(:wrap_options)
      content = super(method, collection, value_method, text_method, options, html_options) + 
        (text.blank? ? '' : explain(method, text))
      wrap_field(wrap, content, wopt)
    end

    def related_collection_select(method, parent_element, collection, value_method, text_method, reference_method, options = {}, html_options = {})
      text = options.delete(:explain)
      wrap = options.delete(:wrap)
      wopt = options.delete(:wrap_options)
      content = @template.related_collection_select(@object_name, method, parent_element, collection, value_method, text_method, reference_method, options, html_options) + 
        (text.blank? ? '' : explain(method, text))
      wrap_field(wrap, content, wopt)
    end

    def country_select(method, priority_countries = nil, options = {}, html_options = {})
      text = options.delete(:explain)
      wrap = options.delete(:wrap)
      wopt = options.delete(:wrap_options)
      content = super(method, priority_zones, options, html_options) + 
        (text.blank? ? '' : explain(method, text))
      wrap_field(wrap, content, wopt)
    end

    def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
      text = options.delete(:explain)
      wrap = options.delete(:wrap)
      wopt = options.delete(:wrap_options)
      content = super(method, priority_zones, options, html_options) + 
        (text.blank? ? '' : explain(method, text))
      wrap_field(wrap, content, wopt)
    end
    
    def wrap_field(tag, content, options = {})
      tag = :div if tag.nil?
      tag ? @template.content_tag(tag, content, options) : content
    end
    protected :wrap_field
  end

end  


ActionView::Helpers::InstanceTag.class_eval do
  def to_label_tag(text = nil, options = {})
    options.stringify_keys!
    name_and_id = options.dup
    add_default_name_and_id(name_and_id)
    options["for"] ||= name_and_id["id"]
    content = (text.blank? ? nil : text.to_s) || method_name.humanize
    content_tag("label", content, options)
  end
end