formize 0.0.2
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.
- data/.document +5 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +74 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/assets/javascripts/formize.js +399 -0
- data/formize.gemspec +64 -0
- data/lib/formize/action_pack.rb +63 -0
- data/lib/formize/definition/element.rb +56 -0
- data/lib/formize/definition/field.rb +67 -0
- data/lib/formize/definition/field_set.rb +40 -0
- data/lib/formize/definition/form.rb +89 -0
- data/lib/formize/definition/form_element.rb +140 -0
- data/lib/formize/definition.rb +5 -0
- data/lib/formize/form_helper.rb +62 -0
- data/lib/formize/generator.rb +598 -0
- data/lib/formize.rb +34 -0
- data/test/helper.rb +9 -0
- data/test/test_formize.rb +7 -0
- metadata +100 -0
@@ -0,0 +1,598 @@
|
|
1
|
+
module Formize
|
2
|
+
|
3
|
+
# Permits to not quote text in inspect method
|
4
|
+
class Code < String
|
5
|
+
|
6
|
+
def inspect
|
7
|
+
self.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
class Generator
|
14
|
+
|
15
|
+
attr_accessor :form, :elements, :record_name, :partial, :controller
|
16
|
+
|
17
|
+
def initialize(form, controller)
|
18
|
+
@form = form
|
19
|
+
@controller = controller
|
20
|
+
@record_name = @form.record_name
|
21
|
+
@elements = form.all_elements
|
22
|
+
@partials = @elements.select{|e| !e.depend_on.nil? or e.options[:new]}
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Generates the controller method from a form object
|
27
|
+
def controller_code
|
28
|
+
code = "def #{form.controller_method_name}\n"
|
29
|
+
|
30
|
+
# Mono_choice search/filter
|
31
|
+
items = form.mono_choices
|
32
|
+
if items.size > 0
|
33
|
+
code << " if params[:unroll]\n"
|
34
|
+
events = form.mono_choices.collect do |mono_choice|
|
35
|
+
event = "if params[:unroll] == '#{mono_choice.html_id}'\n"
|
36
|
+
|
37
|
+
for depended in mono_choice.dependeds
|
38
|
+
df = form.fields[depended[:name]]
|
39
|
+
event << " #{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
|
40
|
+
# locals[df.name.to_sym] = Code.new(df.name)
|
41
|
+
end
|
42
|
+
|
43
|
+
event << mono_choice_search_code(mono_choice).strip.gsub(/^/, ' ') << "\n"
|
44
|
+
event << "end\n"
|
45
|
+
end
|
46
|
+
code << events.collect{|e| e.gsub(/^/, ' ')}.join
|
47
|
+
code << " end\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Dependencies refresh
|
51
|
+
items = @partials
|
52
|
+
if items.size > 0
|
53
|
+
code << " if params[:refresh]\n"
|
54
|
+
code << " #{record_name} = #{form.model.name}.find(params[:id]) if params[:id].to_i > 0\n"
|
55
|
+
code << " #{record_name} ||= #{form.model.name}.new\n"
|
56
|
+
code << " @#{record_name} = #{record_name}\n"
|
57
|
+
events = items.collect do |dependent|
|
58
|
+
event = "if params[:refresh] == '#{dependent.html_id}'\n"
|
59
|
+
locals = {record_name.to_sym => Code.new(record_name)}
|
60
|
+
for depended in dependent.dependeds
|
61
|
+
df = form.fields[depended[:name]]
|
62
|
+
event << " #{record_name}.#{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
|
63
|
+
# locals[df.name.to_sym] = Code.new(df.name)
|
64
|
+
end
|
65
|
+
event << " render(:inline=>'<%=#{dependent.prototype}-%>', :locals=>#{locals.inspect})\n"
|
66
|
+
event << "end\n"
|
67
|
+
end
|
68
|
+
code << events.collect{|e| e.gsub(/^/, ' ')}.join
|
69
|
+
code << " end\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
# End
|
73
|
+
code << "end\n"
|
74
|
+
code.gsub!(/end\s*if/, 'elsif')
|
75
|
+
# raise code
|
76
|
+
list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
|
77
|
+
return code
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
# Generates the view method from a form object
|
83
|
+
def view_code
|
84
|
+
code = ""
|
85
|
+
|
86
|
+
varh = 'html'
|
87
|
+
|
88
|
+
# Build view methods assimilated to partials
|
89
|
+
for element in @partials
|
90
|
+
code << "# #{element.class.name}: #{element.html_id}/#{element.name}\n"
|
91
|
+
code << view_method_code(element, varh)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
code << "\n"
|
96
|
+
code << "def #{form.options[:view_fields_method_name]}(#{form.record_name}=nil)\n"
|
97
|
+
code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
|
98
|
+
code << " #{varh} = ''\n"
|
99
|
+
for element in form.elements
|
100
|
+
code << view_method_call(element, varh).strip.gsub(/^/, ' ') << "\n" #
|
101
|
+
# code << " #{varh} << " << element.method_call_code.gsub(/^/, ' ').strip << "\n"
|
102
|
+
end
|
103
|
+
code << " return #{varh}\n"
|
104
|
+
code << "end\n"
|
105
|
+
|
106
|
+
code << "\n"
|
107
|
+
code << "def #{form.options[:view_form_method_name]}(#{form.record_name}=nil)\n"
|
108
|
+
code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
|
109
|
+
code << " return form_for(#{form.record_name}) do\n"
|
110
|
+
code << " #{form.options[:view_fields_method_name]}(#{form.record_name})\n"
|
111
|
+
code << " end\n"
|
112
|
+
code << "end\n"
|
113
|
+
|
114
|
+
# raise code
|
115
|
+
list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
|
116
|
+
return code
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
def view_partial_code(element, varh='varh')
|
124
|
+
# send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
|
125
|
+
special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
|
126
|
+
code = ""
|
127
|
+
partial_code = send(special_method, element, varh)
|
128
|
+
dependeds = element.dependeds.collect{|d| d[:name]}
|
129
|
+
if dependeds.size > 0
|
130
|
+
for depended in dependeds
|
131
|
+
depended_field = form.fields[depended]
|
132
|
+
code << "#{depended_field.name} = #{form.record_name}.#{depended_field.name}\n"
|
133
|
+
if depended_field.reflection
|
134
|
+
code << "#{depended_field.name} ||= #{field_datasource(depended_field)}.first\n"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
code << "if #{dependeds.join(' and ')}\n"
|
139
|
+
|
140
|
+
code << partial_code.strip.gsub(/^/, ' ') << "\n"
|
141
|
+
|
142
|
+
code << "else\n"
|
143
|
+
code << " #{varh} << content_tag(:div, '', #{wrapper_attrs(element).inspect})\n"
|
144
|
+
code << "end\n"
|
145
|
+
else
|
146
|
+
code = partial_code
|
147
|
+
end
|
148
|
+
return code
|
149
|
+
end
|
150
|
+
|
151
|
+
def view_method_code(element, varh='varh')
|
152
|
+
# send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
|
153
|
+
special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
|
154
|
+
return send(special_method, element, varh) if self.respond_to?(special_method)
|
155
|
+
code = "def #{element.prototype}\n"
|
156
|
+
code << " #{varh} = ''\n"
|
157
|
+
code << view_partial_code(element, varh).strip.gsub(/^/, ' ') << "\n"
|
158
|
+
code << " return #{varh}\n"
|
159
|
+
code << "end\n"
|
160
|
+
return code
|
161
|
+
end
|
162
|
+
|
163
|
+
def view_method_call(element, varh='varh')
|
164
|
+
special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
|
165
|
+
return send(special_method, element, varh) if self.respond_to?(special_method)
|
166
|
+
if @partials.include?(element)
|
167
|
+
return "#{varh} << #{element.prototype}\n"
|
168
|
+
else
|
169
|
+
return view_partial_code(element, varh).strip << "\n"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def wrapper_attrs(element)
|
174
|
+
html_options = (element.respond_to?(:html_options) ? element.html_options : {})
|
175
|
+
html_options[:id] = element.html_id
|
176
|
+
if @partials.include?(element)
|
177
|
+
url = {:controller => controller.controller_name.to_sym, :action=>form.action_name.to_sym, :refresh=>element.html_id}
|
178
|
+
for depended in element.dependeds
|
179
|
+
df = form.fields[depended[:name]]
|
180
|
+
url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
|
181
|
+
end
|
182
|
+
html_options["data-refresh"] = Code.new("url_for(#{url.inspect})")
|
183
|
+
end
|
184
|
+
special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
|
185
|
+
return send(special_method, element, html_options) if self.respond_to?(special_method)
|
186
|
+
return html_options
|
187
|
+
end
|
188
|
+
|
189
|
+
#####################################################################################
|
190
|
+
# F I E L D _ S E T M E T H O D S #
|
191
|
+
#####################################################################################
|
192
|
+
|
193
|
+
def field_set_view_partial_code(field_set, varh='varh')
|
194
|
+
# Initialize html attributes
|
195
|
+
html_options = wrapper_attrs(field_set)
|
196
|
+
|
197
|
+
varc = field_set.html_id # "field_set_#{field_set.html_id}"
|
198
|
+
code = "#{varh} << hard_content_tag(:fieldset, #{html_options.inspect}) do |#{varc}|\n"
|
199
|
+
unless field_set.title.nil?
|
200
|
+
code << " #{varc} << content_tag(:legend, ::I18n.translate('labels.#{field_set.title}'))\n"
|
201
|
+
end
|
202
|
+
for child in field_set.children
|
203
|
+
code << view_method_call(child, varc).strip.gsub(/^/, ' ') << "\n"
|
204
|
+
end
|
205
|
+
code << "end\n"
|
206
|
+
return code
|
207
|
+
end
|
208
|
+
|
209
|
+
# def field_set_view_method_code(field_set, varh='html')
|
210
|
+
# code = "def #{field_set.prototype}\n"
|
211
|
+
# code << " #{varh} = ''\n"
|
212
|
+
# code << field_set_view_partial_code(field_set, varh).strip.gsub(/^/, ' ') << "\n"
|
213
|
+
# code << " return #{varh}\n"
|
214
|
+
# code << "end\n"
|
215
|
+
# return code
|
216
|
+
# end
|
217
|
+
|
218
|
+
# def field_set_view_method_call(field_set, varh='varh')
|
219
|
+
# code = ""
|
220
|
+
# call = if @partials.include?(field_set)
|
221
|
+
# "#{varh} << #{field_set.prototype}\n"
|
222
|
+
# else
|
223
|
+
# field_set_view_partial_code(field_set, varh).strip << "\n"
|
224
|
+
# end
|
225
|
+
|
226
|
+
# if field_set.depend_on
|
227
|
+
# depended_field = form.fields[field_set.depend_on]
|
228
|
+
# code << "#{field_set.depend_on} = #{form.record_name}.#{depended_field.name}\n"
|
229
|
+
# if ref = depended_field.reflection
|
230
|
+
# code << "#{field_set.depend_on} ||= #{field_datasource(depended_field)}.first\n"
|
231
|
+
# end
|
232
|
+
# code << "if #{field_set.depend_on}\n"
|
233
|
+
# code << call.strip.gsub(/^/, ' ') << "\n"
|
234
|
+
# code << "else\n"
|
235
|
+
# opt = {:id=>field_set.html_id, :class=>"waiting", "data-refresh"=>Code.new("url_for(:controller=>:#{controller.controller_name}, :action=>:#{form.action_name}, :refresh=>'#{field_set.html_id}')")}
|
236
|
+
# code << " #{varh} << tag(:div, #{opt.inspect})\n"
|
237
|
+
|
238
|
+
# code << "end\n"
|
239
|
+
# else
|
240
|
+
# code = call
|
241
|
+
# end
|
242
|
+
|
243
|
+
# return code
|
244
|
+
# end
|
245
|
+
|
246
|
+
#####################################################################################
|
247
|
+
# F I E L D M E T H O D S #
|
248
|
+
#####################################################################################
|
249
|
+
|
250
|
+
def field_view_partial_code(field, varh='varh')
|
251
|
+
input_attrs = (field.options[:input_options].is_a?(Hash) ? field.options[:input_options] : {})
|
252
|
+
deps = form.dependents_on(field)
|
253
|
+
if deps.size > 0
|
254
|
+
input_attrs["data-dependents"] = deps.collect{|d| d.html_id}.join(',')
|
255
|
+
end
|
256
|
+
|
257
|
+
# Initialize html attributes
|
258
|
+
html_options = wrapper_attrs(field)
|
259
|
+
|
260
|
+
varc = field.html_id
|
261
|
+
code = "#{varh} << hard_content_tag(:div, #{html_options.inspect}) do |#{varc}|\n"
|
262
|
+
code << " #{varc} << label(:#{form.record_name}, :#{field.name}, nil, :class=>'attr')\n"
|
263
|
+
code << " #{form.record_name}.#{field.name} ||= #{field.default.inspect}\n" if field.default
|
264
|
+
code << self.send("field_#{field.type}_input", field, input_attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
265
|
+
code << "end\n"
|
266
|
+
return code
|
267
|
+
end
|
268
|
+
|
269
|
+
# def field_view_method_code(field, varh='html')
|
270
|
+
# code = "def #{field.prototype}\n"
|
271
|
+
# code << " #{varh} = ''\n"
|
272
|
+
# code << field_view_partial_code(field, varh).strip.gsub(/^/, ' ') << "\n"
|
273
|
+
# code << " return #{varh}\n"
|
274
|
+
# code << "end\n"
|
275
|
+
# return code
|
276
|
+
# end
|
277
|
+
|
278
|
+
# def field_view_method_call(field, varh='varh')
|
279
|
+
# code = ""
|
280
|
+
# call = if @partials.include?(field)
|
281
|
+
# "#{varh} << #{field.prototype}\n"
|
282
|
+
# else
|
283
|
+
# field_view_partial_code(field, varh).strip << "\n"
|
284
|
+
# end
|
285
|
+
|
286
|
+
# if field.depend_on
|
287
|
+
# depended_field = form.fields[field.depend_on]
|
288
|
+
# code << "#{field.depend_on} = #{form.record_name}.#{depended_field.name}\n"
|
289
|
+
# code << "if #{field.depend_on}\n"
|
290
|
+
# code << call.strip.gsub(/^/, ' ') << "\n"
|
291
|
+
# code << "else\n"
|
292
|
+
# attrs = field_wrapper_attrs(field)
|
293
|
+
# attrs[:class] = "#{attrs[:class]} waiting".strip
|
294
|
+
# code << " #{varh} << tag(:div, #{attrs.inspect})\n"
|
295
|
+
# code << "end\n"
|
296
|
+
# else
|
297
|
+
# code = call
|
298
|
+
# end
|
299
|
+
|
300
|
+
# return code
|
301
|
+
# end
|
302
|
+
|
303
|
+
|
304
|
+
def field_datasource(field)
|
305
|
+
source = field.source
|
306
|
+
source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
|
307
|
+
if source.is_a?(Array)
|
308
|
+
return "#{source[0]}.#{field.choices}"
|
309
|
+
elsif source == :foreign_class
|
310
|
+
return "#{field.reflection.class_name}.#{field.choices}"
|
311
|
+
elsif source == :class
|
312
|
+
return "#{form.model.name}.#{field.choices}"
|
313
|
+
else
|
314
|
+
return "#{source}.#{field.choices}"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def field_datasource_class_name(field)
|
319
|
+
source = field.source
|
320
|
+
source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
|
321
|
+
if source.is_a?(Array)
|
322
|
+
return source[1]
|
323
|
+
elsif source == :foreign_class
|
324
|
+
return field.reflection.class_name
|
325
|
+
elsif source == :class
|
326
|
+
return form.model.name
|
327
|
+
else
|
328
|
+
return source.to_s.classify
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def field_input_options(field)
|
333
|
+
end
|
334
|
+
|
335
|
+
def field_wrapper_attrs(field, html_options={})
|
336
|
+
html_options[:class] = "field #{html_options[:class]}".strip
|
337
|
+
html_options[:class] = "#{html_options[:class]} #{field.type.to_s.gsub('_', '-')}".strip
|
338
|
+
html_options[:class] = "#{html_options[:class]} required".strip if field.required
|
339
|
+
return html_options
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
def field_check_box_input(field, attrs={}, varc='varc')
|
346
|
+
return "#{varc} << check_box(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
347
|
+
end
|
348
|
+
|
349
|
+
def field_choice_input(field, attrs={}, varc='varc')
|
350
|
+
code = if field.choices.size <= Formize.radio_count_max
|
351
|
+
field_radio_input(field, attrs, varc)
|
352
|
+
else
|
353
|
+
field_select_input(field, attrs, varc)
|
354
|
+
end
|
355
|
+
return code
|
356
|
+
end
|
357
|
+
|
358
|
+
def field_date_input(field, attrs={}, varc='varc')
|
359
|
+
attrs[:size] ||= 16
|
360
|
+
return "#{varc} << date_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
361
|
+
end
|
362
|
+
|
363
|
+
def field_datetime_input(field, attrs={}, varc='varc')
|
364
|
+
attrs[:size] ||= 16
|
365
|
+
return "#{varc} << datetime_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
366
|
+
end
|
367
|
+
|
368
|
+
def field_label_input(field, attrs={}, varc='varc')
|
369
|
+
attrs[:class] = (attrs[:class]+" readonly").strip
|
370
|
+
return "#{varc} << content_tag(:span, @:#{field.record_name}.#{field.method}, #{attrs.inspect})\n"
|
371
|
+
end
|
372
|
+
|
373
|
+
def field_numeric_input(field, attrs={}, varc='varc')
|
374
|
+
attrs[:size] ||= 16
|
375
|
+
return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
376
|
+
end
|
377
|
+
|
378
|
+
def field_password_input(field, attrs={}, varc='varc')
|
379
|
+
attrs[:size] ||= 24
|
380
|
+
return "#{varc} << password_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
381
|
+
end
|
382
|
+
|
383
|
+
def field_radio_input(field, attrs={}, varc='varc')
|
384
|
+
return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field.choices.inspect}, #{attrs.inspect})\n"
|
385
|
+
# return "#{varc} << " << field.choices.collect{|x| "content_tag(:span, radio_button(:#{field.record_name}, :#{field.method}, #{x[1].inspect}) << ' ' << content_tag(:label, #{x[0].inspect}, :for=>'#{field.input_id}_#{x[1]}'), :class=>'rad')"}.join(" << ") << "\n"
|
386
|
+
end
|
387
|
+
|
388
|
+
def field_select_input(field, attrs={}, varc='varc')
|
389
|
+
if (include_blank = attrs.delete(:include_blank)).is_a? String
|
390
|
+
field.choices.insert(0, [include_blank, ''])
|
391
|
+
end
|
392
|
+
return "#{varc} << select(:#{field.record_name}, :#{field.method}), #{field.choices.inspect}, #{attrs.inspect})\n"
|
393
|
+
end
|
394
|
+
|
395
|
+
def field_mono_choice_input(field, attrs={}, varc='varc')
|
396
|
+
source_model = field_datasource_class_name(field).constantize
|
397
|
+
reflection = source_model.reflections[field.choices]
|
398
|
+
if reflection.nil?
|
399
|
+
raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
|
400
|
+
end
|
401
|
+
count = "#{field.choices}_count"
|
402
|
+
select_first_if_empty = " #{record_name}.#{field.name} ||= #{field_datasource(field)}.first\n"
|
403
|
+
code = "#{count} = #{field_datasource(field)}.count\n"
|
404
|
+
code << "if (#{count} == 0)\n"
|
405
|
+
code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
406
|
+
code << "elsif (#{count} <= #{Formize.radio_count_max})\n"
|
407
|
+
code << select_first_if_empty
|
408
|
+
code << field_mono_radio_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
409
|
+
if reflection.options[:finder_sql].nil?
|
410
|
+
code << "elsif (#{count} <= #{Formize.select_count_max})\n"
|
411
|
+
code << select_first_if_empty
|
412
|
+
code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
413
|
+
code << "else\n"
|
414
|
+
code << select_first_if_empty
|
415
|
+
code << field_mono_unroll_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
416
|
+
else
|
417
|
+
code << "else\n"
|
418
|
+
code << select_first_if_empty
|
419
|
+
code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
|
420
|
+
end
|
421
|
+
code << "end\n"
|
422
|
+
|
423
|
+
new_item_url = field.options.delete(:new)
|
424
|
+
if new_item_url.is_a? Symbol
|
425
|
+
new_item_url = {:controller=>new_item_url.to_s.pluralize.to_sym}
|
426
|
+
elsif new_item_url.is_a? TrueClass
|
427
|
+
new_item_url = {}
|
428
|
+
end
|
429
|
+
|
430
|
+
if new_item_url.is_a?(Hash)
|
431
|
+
for k, v in new_item_url
|
432
|
+
new_item_url[k] = Code.new(v) if v.is_a?(String)
|
433
|
+
end
|
434
|
+
edit_item_url = {} unless edit_item_url.is_a? Hash
|
435
|
+
if field.method.to_s.match(/_id$/) and refl = form.model.reflections[field.method.to_s[0..-4].to_sym]
|
436
|
+
new_item_url[:controller] ||= refl.class_name.underscore.pluralize
|
437
|
+
edit_item_url[:controller] ||= new_item_url[:controller]
|
438
|
+
end
|
439
|
+
new_item_url[:action] ||= :new
|
440
|
+
edit_item_url[:action] ||= :edit
|
441
|
+
data = field.options.delete(:update)||field.html_id
|
442
|
+
html_options = {"data-add-item"=>data, :class=>"icon im-new"}
|
443
|
+
code << "#{varc} << content_tag(:span, content_tag(:span, link_to(tg(:new), #{new_item_url.inspect}, #{html_options.inspect}).html_safe, :class=>:tool).html_safe, :class=>\"toolbar mini-toolbar\") if authorized?(#{new_item_url.inspect})\n"
|
444
|
+
end
|
445
|
+
return code
|
446
|
+
end
|
447
|
+
|
448
|
+
def field_mono_radio_input(field, attrs={}, varc='varc')
|
449
|
+
return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
|
450
|
+
end
|
451
|
+
|
452
|
+
def field_mono_select_input(field, attrs={}, varc='varc')
|
453
|
+
return "#{varc} << select(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
|
454
|
+
end
|
455
|
+
|
456
|
+
def field_mono_unroll_input(field, attrs={}, varc='varc')
|
457
|
+
options = {}
|
458
|
+
options[:label] ||= Code.new("Proc.new{|r| \"#{mono_choice_label(field, 'r')}\"}")
|
459
|
+
url = {:controller=>controller.controller_name, :action=>form.action_name, :unroll=>field.html_id}
|
460
|
+
for depended in field.dependeds
|
461
|
+
df = form.fields[depended[:name]]
|
462
|
+
url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
|
463
|
+
end
|
464
|
+
return "#{varc} << unroll(:#{field.record_name}, :#{field.method}, url_for(#{url.inspect}), #{options.inspect}, #{attrs.inspect})"
|
465
|
+
end
|
466
|
+
|
467
|
+
def field_string_input(field, attrs={}, varc='varc')
|
468
|
+
attrs[:size] ||= 24
|
469
|
+
if field.column and !field.column.limit.nil?
|
470
|
+
attrs[:size] = field.column.limit if field.column.limit<attrs[:size]
|
471
|
+
attrs[:maxlength] = field.column.limit
|
472
|
+
end
|
473
|
+
return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
474
|
+
end
|
475
|
+
|
476
|
+
def field_text_area_input(field, attrs={}, varc='varc')
|
477
|
+
attrs[:cols] ||= 40
|
478
|
+
attrs[:rows] ||= 3
|
479
|
+
attrs[:class] = "#{attrs[:class]} #{attrs[:cols]==80 ? :code : nil}".strip
|
480
|
+
return "#{varc} << text_area(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
|
481
|
+
end
|
482
|
+
|
483
|
+
|
484
|
+
|
485
|
+
|
486
|
+
|
487
|
+
|
488
|
+
protected
|
489
|
+
|
490
|
+
def sanitize_conditions(value)
|
491
|
+
if value.is_a? Array
|
492
|
+
if value.size==1 and value[0].is_a? String
|
493
|
+
value[0].to_s
|
494
|
+
else
|
495
|
+
value.inspect
|
496
|
+
end
|
497
|
+
elsif value.is_a? String
|
498
|
+
'"'+value.gsub('"','\"')+'"'
|
499
|
+
elsif [Date, DateTime].include? value.class
|
500
|
+
'"'+value.to_formatted_s(:db)+'"'
|
501
|
+
else
|
502
|
+
value.to_s
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
|
507
|
+
def mono_choice_label(choice, varr='record')
|
508
|
+
return "\#\{#{varr}.#{choice.item_label}\}"
|
509
|
+
end
|
510
|
+
|
511
|
+
def mono_choice_search_code(field)
|
512
|
+
source_model = field_datasource_class_name(field).constantize
|
513
|
+
reflection = source_model.reflections[field.choices]
|
514
|
+
if reflection.nil?
|
515
|
+
raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
|
516
|
+
end
|
517
|
+
model = reflection.class_name.constantize
|
518
|
+
foreign_record = model.name.underscore
|
519
|
+
foreign_records = "#{source_model.name.underscore}_#{field.choices}"
|
520
|
+
options = field.options
|
521
|
+
attributes = field.search_attributes
|
522
|
+
attributes = [attributes] unless attributes.is_a? Array
|
523
|
+
attributes_hash = {}
|
524
|
+
attributes.each_index do |i|
|
525
|
+
attribute = attributes[i]
|
526
|
+
attributes[i] = [
|
527
|
+
(attribute.to_s.match(/\./) ? attribute.to_s : model.table_name+'.'+attribute.to_s.split(/\:/)[0]),
|
528
|
+
(attribute.to_s.match(/\:/) ? attribute.to_s.split(/\:/)[1] : (options[:filter]||'%X%')),
|
529
|
+
'_a'+i.to_s]
|
530
|
+
attributes_hash[attributes[i][2]] = attributes[i][0]
|
531
|
+
end
|
532
|
+
query = []
|
533
|
+
parameters = ''
|
534
|
+
if options[:conditions].is_a? Hash
|
535
|
+
options[:conditions].each do |key, value|
|
536
|
+
query << (key.is_a?(Symbol) ? model.table_name+"."+key.to_s : key.to_s)+'=?'
|
537
|
+
parameters += ', ' + sanitize_conditions(value)
|
538
|
+
end
|
539
|
+
elsif options[:conditions].is_a? Array
|
540
|
+
conditions = options[:conditions]
|
541
|
+
case conditions[0]
|
542
|
+
when String # SQL
|
543
|
+
# query << '["'+conditions[0].to_s+'"'
|
544
|
+
query << conditions[0].to_s
|
545
|
+
parameters += ', '+conditions[1..-1].collect{|p| sanitize_conditions(p)}.join(', ') if conditions.size>1
|
546
|
+
# query << ')'
|
547
|
+
else
|
548
|
+
raise Exception.new("First element of an Array can only be String or Symbol.")
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
select = (model.table_name+".id AS id, "+attributes_hash.collect{|k,v| v+" AS "+k}.join(", ")).inspect
|
553
|
+
joins = options[:joins] ? ", :joins=>"+options[:joins].inspect : ""
|
554
|
+
|
555
|
+
code = ""
|
556
|
+
code << "conditions = [#{query.join(' AND ').inspect+parameters}]\n"
|
557
|
+
code << "search = params[:search]\n"
|
558
|
+
code << "words = search.lower.split(/[\\s\\,]+/)\n"
|
559
|
+
code << "if words.size > 0\n"
|
560
|
+
code << " conditions[0] << '#{' AND ' if query.size>0}('\n"
|
561
|
+
code << " words.each_index do |index|\n"
|
562
|
+
code << " word = words[index].to_s\n"
|
563
|
+
code << " conditions[0] << ') AND (' if index > 0\n"
|
564
|
+
|
565
|
+
if ActiveRecord::Base.connection.adapter_name == "MySQL"
|
566
|
+
code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS CHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
|
567
|
+
else
|
568
|
+
code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS VARCHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
|
569
|
+
end
|
570
|
+
|
571
|
+
code << " conditions += ["+attributes.collect{|key| key[1].inspect.gsub('X', '"+word+"').gsub(/(^\"\"\+|\+\"\"\+|\+\"\")/, '')}.join(", ")+"]\n"
|
572
|
+
code << " end\n"
|
573
|
+
code << " conditions[0] << ')'\n"
|
574
|
+
code << "end\n"
|
575
|
+
order = ", :order=>"+attributes.collect{|key| "#{key[0]} ASC"}.join(', ').inspect
|
576
|
+
limit = ", :limit=>"+(options[:limit]||12).to_s
|
577
|
+
partial = options[:partial]
|
578
|
+
|
579
|
+
html = "<ul><%for #{foreign_record} in #{foreign_records}-%><li id='<%=#{foreign_record}.id-%>'>"
|
580
|
+
html << "<%content=#{foreign_record}.#{field.item_label}-%>"
|
581
|
+
# html << "<%content="+attributes.collect{|key| "#{foreign_record}['#{key[2]}'].to_s"}.join('+", "+')+" -%>"
|
582
|
+
if partial
|
583
|
+
html << "<%=render(:partial=>#{partial.inspect}, :locals =>{:#{foreign_record}=>#{foreign_record}, :content=>content, :search=>search})-%>"
|
584
|
+
else
|
585
|
+
html << "<%=highlight(content, search)-%>"
|
586
|
+
end
|
587
|
+
html << '</li><%end-%></ul>'
|
588
|
+
|
589
|
+
code << "#{foreign_records} = #{field_datasource(field)}.find(:all, :conditions=>conditions"+joins+order+limit+")\n"
|
590
|
+
code << "render :inline=>#{html.inspect}, :locals=>{:#{foreign_records}=>#{foreign_records}, :search=>search}\n"
|
591
|
+
return code
|
592
|
+
end
|
593
|
+
|
594
|
+
|
595
|
+
|
596
|
+
end
|
597
|
+
|
598
|
+
end
|
data/lib/formize.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Formize provides controller's side defined forms.
|
2
|
+
module Formize
|
3
|
+
|
4
|
+
def self.configure(name, value = nil)
|
5
|
+
unless self.respond_to?("#{name}=")
|
6
|
+
mattr_accessor(name)
|
7
|
+
self.send("#{name}=", value)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# default_source used by mono_choices:
|
12
|
+
# - :foreign_class : Class of foreign object
|
13
|
+
# - :class : Class of object
|
14
|
+
# - "variable_name" or :variable_name : A variable (Class name is computed with the name
|
15
|
+
# of the variable. Example: "product" will have "Product" class_name. If class_name
|
16
|
+
# has to be different, use next possibility.
|
17
|
+
# - ["variable_name", "class_name"] : Code used to select source with the
|
18
|
+
# class_name of the variable.
|
19
|
+
configure :default_source, :foreign_class
|
20
|
+
|
21
|
+
# How many radio can be displayed before to become a +select+
|
22
|
+
configure :radio_count_max, 3
|
23
|
+
|
24
|
+
# How many select options can be displayed before to become a +unroll+
|
25
|
+
configure :select_count_max, 7
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'action_view'
|
30
|
+
require 'formize/definition'
|
31
|
+
require 'formize/generator'
|
32
|
+
require 'formize/form_helper'
|
33
|
+
require 'formize/action_pack'
|
34
|
+
|
data/test/helper.rb
ADDED