Class: FormBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/yodel/models/pages/form_builder.rb

Constant Summary collapse

MONTHS =
[
  [1, "January"],
  [2, "February"],
  [3, "March"],
  [4, "April"],
  [5, "May"],
  [6, "June"],
  [7, "July"],
  [8, "August"],
  [9, "September"],
  [10, "October"],
  [11, "November"],
  [12, "December"]
]

Instance Method Summary collapse

Constructor Details

#initialize(record, action, options = {}, &block) ⇒ FormBuilder

Returns a new instance of FormBuilder.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/yodel/models/pages/form_builder.rb', line 18

def initialize(record, action, options={}, &block)
  @record = record
  @options = options
  @block = block
  @action = action
  
  @remote = options.delete(:remote)
  @method = options.delete(:method) || 'post'
  @params = options.delete(:params) || {}
  @embedded_record = options.delete(:embedded_record)
  @blank_record = options.delete(:blank_record)
  @prefix = options.delete(:prefix)
  @id = @params.delete(:id) || options.delete(:id) || "form_for_#{record.id}"
  
  # js functions
  @success_function = options.delete(:success)
  @errors_function  = options.delete(:errors)
  @failure_function = options.delete(:failure)
end

Instance Method Details

#blank_record?Boolean

Returns:

  • (Boolean)


266
267
268
# File 'lib/yodel/models/pages/form_builder.rb', line 266

def blank_record?
  @blank_record
end

#errors(&block) ⇒ Object



252
253
254
255
# File 'lib/yodel/models/pages/form_builder.rb', line 252

def errors(&block)
  @errors_function = Ember::Template.content_from_block(block).join
  ''
end

#failure(&block) ⇒ Object



257
258
259
260
# File 'lib/yodel/models/pages/form_builder.rb', line 257

def failure(&block)
  @failure_function = Ember::Template.content_from_block(block).join
  ''
end

#field(name, options = {}, &block) ⇒ Object



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
# File 'lib/yodel/models/pages/form_builder.rb', line 59

def field(name, options={}, &block)
  invalid = @record.errors.key?(name.to_s)
  field_name = name.to_s
  field = @record.field(field_name)
  input_name = (options.delete(:name) || field_name).to_s
  input_name = "#{@prefix}[][#{input_name}]" if @prefix
  value = options.delete(:value) || @record.get(field_name)
  type = options.delete(:as) || field.default_input_type
  
  case type
  when :text, :password, :hidden
    value = nil if type == :password
    value = value.id if value.is_a?(AbstractRecord)
    value = value.to_s("F") if value.is_a?(BigDecimal)
    element = build_element(:input, {type: type.to_s, value: value.to_s})
    
  when :textarea
    element = build_element(:textarea, {}, value.to_s)
    
  when :html
    element = build_element(:textarea, {class: 'html'}, value.to_s)
    
  when :file, :image
    elements = []
    elements << build_element(:input, {type: 'hidden', name: input_name + '[_action]', value: 'set'})
    if type == :file
      elements << build_element(:p, {}, "File: <span>#{value && value.name || 'none'}</span>")
    else
      if !value.nil? && value.exist?
        src = value.url(:admin_thumb).to_s
        display = 'block'
      else
        src = ''
        display = 'none'
      end
      elements << build_element(:div, {class: 'image_preview'}, [build_element(:img, {src: src, style: "display: #{display}"})])
      elements << build_element(:p, {}, "Image: <span>#{(value && value.name) || 'none'}</span>")
    end
    elements << build_element(:input, {type: 'checkbox', name: input_name + '[_action]', value: 'clear'})
    elements << build_element(:span, {}, "Delete")
    elements << build_element(:input, {type: 'file', value: value.name, name: input_name + '[_value]'})
    element = build_element(:span, {}, elements)
    
  when :radio
    base = {type: 'radio', name: input_name}
    true_button   = build_element(:input, base.merge(condition('checked', value, ['true', true])))
    false_button  = build_element(:input, base.merge(condition('checked', value, ['false', false])))
    true_text     = options.delete(:true) || 'Yes'
    false_text    = options.delete(:false) || 'No'
    element = build_element(:span, {}, [true_text, true_button, false_text, false_button])
    
  when :enum
    element = build_select(value, field.options['options'], show_blank: field.show_blank, blank_text: field.blank_text)
    
  when :store_one
    element = build_select(value, field.record_options(@record), show_blank: field.show_blank, blank_text: field.blank_text, group_by: field.group_by, name_field: 'name', value_field: 'id')
    
  when :store_many
    element = build_select(value.collect(&:id), field.record_options(@record), show_blank: false, name_field: 'name', value_field: 'id', multiple: true)
    input_name += '[]'
    
  when :date, :datetime
    # day
    day_select = build_select(value.try(:day).to_s, (1..31), show_blank: true, blank_text: '', name_field: 'to_s', value_field: 'to_s')
    day_select.set_attribute(:name, input_name + '[day]')
    day_select.set_attribute(:id, input_name + '_day_')
    
    # month
    month_select = build_select(value.try(:month).to_s, MONTHS, show_blank: true, blank_text: '', name_field: 'last', value_field: 'first')
    month_select.set_attribute(:name, input_name + '[month]')
    month_select.set_attribute(:id, input_name + '_month_')
    
    # year
    year_select = build_select(value.try(:year).to_s, ((Time.now.year - 100)..(Time.now.year + 10)), show_blank: true, blank_text: '', name_field: 'to_s', value_field: 'to_s')
    year_select.set_attribute(:name, input_name + '[year]')
    year_select.set_attribute(:id, input_name + '_year_')
    
    elements = [day_select, month_select, year_select]
    if type == :datetime
      # hour
      hour_select = build_select(value.try(:hour).to_s, (0..23), show_blank: true, blank_text: '', name_field: 'to_s', value_field: 'to_s')
      hour_select.set_attribute(:name, input_name + '[hour]')
      hour_select.set_attribute(:id, input_name + '_hour_')
      
      # minute
      min_select = build_select(value.try(:min).to_s, (0..59), show_blank: true, blank_text: '', name_field: 'to_s', value_field: 'to_s')
      min_select.set_attribute(:name, input_name + '[min]')
      min_select.set_attribute(:id, input_name + '_min_')
      
      elements += [hour_select, min_select]
    end
    
    element = build_element(:span, {}, elements)
    
  when :embedded
    elements = []
    
    if value.respond_to?(:each)
      value.each do |document|
        elements << self.class.new(document, @action, {embedded_record: field, prefix: name, id: @id}, &block).render
      end
    else
      elements << self.class.new(value, @action, {embedded_record: field, prefix: name, id: @id}, &block).render
    end

    if options.delete(:blank_record)
      elements << self.class.new(value.new, @action, {embedded_record: field, blank_record: true, prefix: name, id: @id}, &block).render
    end
    
    if block_given?
      buffer = Ember::Template.buffer_from_block(@block)
      buffer << build_element(:input, {'type' => 'hidden', 'data-field' => input_name}).to_s
    else
      elements << build_element(:input, {'type' => 'hidden', 'data-field' => input_name})
      element = build_element(:span, {}, elements)
    end
  end
  
  element.tap do |element|
    class_name = invalid ? 'invalid' : (@record.new? ? 'new' : 'valid')
    class_name += " field-type-#{field.options['type']}"
    element.set_attribute(:id, input_name.gsub(/\W/, '_'))
    element.set_attribute(:name, input_name)
    element.set_attribute(:class, class_name)
    element.set_attribute(:placeholder, field.placeholder || '')
    element.set_attribute('data-field', input_name)
    options.each do |name, value|
      element.set_attribute(name.to_s, value)
    end
  end if element
end

#field_row(name, field = nil) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/yodel/models/pages/form_builder.rb', line 44

def field_row(name, field=nil)
  field = @record.fields[name.to_s] if field.nil?
  html = "<div class='contains-field-type-#{field.options['type']}'>"
  html << label(name).to_s << "<div>"
  
  if field.default_input_type == :embedded
    html << field(name, blank_record: true).to_s
  else
    html << field(name).to_s
  end
  
  html << status(name).to_s << "</div></div>"
end

#form_for_section(section) ⇒ Object



38
39
40
41
42
# File 'lib/yodel/models/pages/form_builder.rb', line 38

def form_for_section(section)
  section.displayed_fields.collect do |field|
    field_row(field.name, field)
  end.join('')
end

#label(name, text = nil, options = {}) ⇒ Object



199
200
201
202
# File 'lib/yodel/models/pages/form_builder.rb', line 199

def label(name, text=nil, options={})
  text ||= name.to_s.humanize
  build_element(:label, {:for => name.to_s}, text)
end

#prefixObject



195
196
197
# File 'lib/yodel/models/pages/form_builder.rb', line 195

def prefix
  @prefix
end

#progress(&block) ⇒ Object



238
239
240
241
242
243
244
245
# File 'lib/yodel/models/pages/form_builder.rb', line 238

def progress(&block)
  Ember::Template.wrap_content_block(block) do |content|
    Hpricot::Elem.new('span', {
      :class => 'yodel-form-activity',
      :style => 'visibility: hidden'
    }, [Hpricot::Text.new(content.join)])
  end
end

#recordObject



191
192
193
# File 'lib/yodel/models/pages/form_builder.rb', line 191

def record
  @record
end

#renderObject



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/yodel/models/pages/form_builder.rb', line 270

def render
  # render a default form
  if @block.nil?
    if @embedded_record
      form_for_section(@record.field_sections[nil])
    else
      form_element(@record.field_sections[nil])
    end
  
  # render a user supplied form
  else
    if @embedded_record
      buffer = Ember::Template.buffer_from_block(@block)
      buffer << Ember::Template.content_from_block(@block, self)
    else
      Ember::Template.wrap_content_block(@block, self) {|content| form_element(content.join)}
    end
  end
  
end

#status(*params) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/yodel/models/pages/form_builder.rb', line 205

def status(*params)
  if params.last.is_a?(Hash)
    handles = params[0...-1]
    options = params.last
  else
    handles = params
    options = {}
  end
  
  handles       = handles.collect(&:to_s)
  name          = options.delete(:as) || handles.first
  new_text      = options.delete(:new).to_s
  valid_text    = options.delete(:valid).to_s
  invalid_text  = options.delete(:invalid).to_s
  
  if @record.errors.empty?
    state = 'new'
    message = new_text
  elsif handles.any? {|name| @record.errors.key?(name)}
    state = 'invalid'
    unless invalid_text.blank?
      message = invalid_text
    else
      message = handles.collect {|name| @record.errors.summarise[name]}.compact.join(', ')
    end
  else
    state = 'valid'
    message = valid_text
  end
  
  render_status(name, handles.join(' '), message, state, new_text, valid_text, invalid_text)
end

#statuses(&block) ⇒ Object



262
263
264
# File 'lib/yodel/models/pages/form_builder.rb', line 262

def statuses(&block)
  @status_template = block
end

#success(&block) ⇒ Object



247
248
249
250
# File 'lib/yodel/models/pages/form_builder.rb', line 247

def success(&block)
  @success_function = Ember::Template.content_from_block(block).join
  ''
end