forme 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +56 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +646 -69
- data/Rakefile +5 -4
- data/lib/forme.rb +433 -328
- data/lib/forme/rails.rb +4 -4
- data/lib/forme/version.rb +1 -1
- data/lib/sequel/plugins/forme.rb +43 -94
- data/spec/forme_coverage.rb +13 -0
- data/spec/forme_spec.rb +315 -4
- data/spec/rails_integration_spec.rb +31 -1
- data/spec/sequel_plugin_spec.rb +28 -11
- data/spec/sinatra_integration_spec.rb +1 -1
- data/spec/spec_helper.rb +20 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 610c1c28c2ed6fc3c4f36d520c4e67fea4fa9c1f
|
4
|
+
data.tar.gz: 7bb48306b738007c7c40c0673ad964c94f1e4c0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6076239cb78c5f4ad271fb77d5b65947f75899243633e49281ae0d2c350799d134d4deb542aa8129e912f427a0a46ce195bd5f21d34904ab1505e738aab75dd
|
7
|
+
data.tar.gz: de392606364637b2b8999151ff18854bbc0e0b2ec62d54f123ce563b986814e5311154b7c825687274dc16f4e5b579cc0f6a44f5a37c34d08338ee93214cd939
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,59 @@
|
|
1
|
+
=== 0.10.0 (2014-07-01)
|
2
|
+
|
3
|
+
* Use #[] instead of #send to get input value for object forms if object is a hash (jeremyevans)
|
4
|
+
|
5
|
+
* Add Form#each_obj, for iterating over an Enumerable of objects, using with_obj for each object (jeremyevans)
|
6
|
+
|
7
|
+
* Add Form#with_obj, for changing a Form's object and namespace temporarily (jeremyevans)
|
8
|
+
|
9
|
+
* Support changing the namespace for a Form temporarily using with_opts(:namespace=>['ns1', 'ns2']) (jeremyevans)
|
10
|
+
|
11
|
+
* Use current namespace for form object inputs if :id/:name/:key is not specified (jeremyevans)
|
12
|
+
|
13
|
+
* Remove SequelForm#nested_associations accessor methods, no longer necessary (jeremyevans)
|
14
|
+
|
15
|
+
* Support changing the object for a Form temporarily using with_opts(:obj=>new_obj) (jeremyevans)
|
16
|
+
|
17
|
+
* Add :table, :tr, :ol, and :fieldset_ol wrappers, which automatically set wrapper and inputs_wrapper appropriately (jeremyevans)
|
18
|
+
|
19
|
+
* Add subform :grid option in Sequel plugin, for more compact editing of nested *_to_many associations (jeremyevans)
|
20
|
+
|
21
|
+
* Make table inputs_wrapper accept a :labels option and automatically set up th tags with the labels for each column (jeremyevans)
|
22
|
+
|
23
|
+
* Form#inputs now accepts a :nested_inputs_wrapper option to set default inputs_wrapper transformer inside the block (jeremyevans)
|
24
|
+
|
25
|
+
* Add tr inputs_wrapper and td wrapper, for horizontal layout of inputs inside a table (jeremyevans)
|
26
|
+
|
27
|
+
* Form#inputs now accepts transformer options (e.g :wrapper) and automatically calls with_opts (jeremyevans)
|
28
|
+
|
29
|
+
* Remove Form#format and Form#serialize (jeremyevans)
|
30
|
+
|
31
|
+
* Remove Form#{formatter,labeler,error_handler,wrapper,inputs_wrapper} accessors (jeremyevans)
|
32
|
+
|
33
|
+
* Add Form.with_opts method to override opts for the given block (jeremyevans)
|
34
|
+
|
35
|
+
* Remove Form#use_serializer and Serializer module (jeremyevans)
|
36
|
+
|
37
|
+
* table inputs_wrapper now respects the :legend and :legend_attr options, using a caption (jeremyevans)
|
38
|
+
|
39
|
+
* ol, div, and table inputs_wrappers now respect the :attr option (jeremyevans)
|
40
|
+
|
41
|
+
* Make subform always use the inputs_wrapper, even if :inputs is not given (jeremyevans)
|
42
|
+
|
43
|
+
* Allow input_defaults to work with symbol keys for inputs that use symbol types (jeremyevans)
|
44
|
+
|
45
|
+
* Support Form :values option, for automatically setting value attributes for inputs from submitted params (jeremyevans)
|
46
|
+
|
47
|
+
* Support :autofocus option for setting autofocus attribute, similar to :required and :disabled (jeremyevans)
|
48
|
+
|
49
|
+
* Add Forme.default_add_blank_prompt for setting default prompt used for :add_blank option (jeremyevans)
|
50
|
+
|
51
|
+
* Support radioset and checkboxset Input types (jeremyevans)
|
52
|
+
|
53
|
+
* Support :key and :key_id options for Inputs, for automatically setting name/id attributes based on current namespace (jeremyevans)
|
54
|
+
|
55
|
+
* Move namespace handling from Sequel plugin into the core (jeremyevans)
|
56
|
+
|
1
57
|
=== 0.9.2 (2014-04-10)
|
2
58
|
|
3
59
|
* Make association_select_options compatible with Sequel 4.10+ (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -7,21 +7,83 @@ Forme is a HTML forms library for ruby with the following goals:
|
|
7
7
|
3. Support forms both with and without related objects
|
8
8
|
4. Allow compiling down to different types of output
|
9
9
|
|
10
|
-
=
|
11
|
-
|
12
|
-
|
10
|
+
= Introduction
|
11
|
+
|
12
|
+
Forme is designed to make creating HTML forms easier. Flexibility and
|
13
|
+
simplicity are primary objectives. The basic usage involves creating
|
14
|
+
a <tt>Forme::Form</tt> instance, and calling +input+ and +tag+ methods
|
15
|
+
to return html strings for widgets, but it could also be used for
|
16
|
+
serializing to other formats, or even as a DSL for a GUI application.
|
17
|
+
|
18
|
+
In order to be flexible, Forme stores tags in abstract form until
|
19
|
+
output is requested. There are two separate abstract <i>forms</i> that Forme
|
20
|
+
uses. One is <tt>Forme::Input</tt>, and the other is <tt>Forme::Tag</tt>.
|
21
|
+
<tt>Forme::Input</tt> is a high level abstract form, while <tt>Forme::Tag</tt>
|
22
|
+
is a low level abstract form.
|
23
|
+
|
24
|
+
The difference between <tt>Forme::Input</tt> and <tt>Forme::Tag</tt>
|
25
|
+
is that <tt>Forme::Tag</tt> directly represents the underlying html
|
26
|
+
tag, containing a type, optional attributes, and children, while the
|
27
|
+
<tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
|
28
|
+
For example, these both compile by default to the same select tag:
|
29
|
+
|
30
|
+
f.input(:select, :options=>[['foo', 1]])
|
31
|
+
# or
|
32
|
+
f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
|
33
|
+
|
34
|
+
The processing of high level <tt>Forme::Input</tt>s into raw html
|
35
|
+
data is broken down to the following steps (called transformers):
|
36
|
+
|
37
|
+
* +Formatter+: converts a <tt>Forme::Input</tt> instance into a
|
38
|
+
<tt>Forme::Tag</tt> instance (or array of them).
|
39
|
+
* +ErrorHandler+: If the <tt>Forme::Input</tt> instance has a error,
|
40
|
+
takes the formatted tag and marks it as having the error.
|
41
|
+
* +Labeler+: If the <tt>Forme::Input</tt> instance has a label,
|
42
|
+
takes the formatted output and labels it.
|
43
|
+
* +Wrapper+: Takes the output of the formatter, labeler, and
|
44
|
+
error_handler transformers, and wraps it in another tag (or just
|
45
|
+
returns it unmodified).
|
46
|
+
* +Serializer+: converts a <tt>Forme::Tag</tt> instance into an
|
47
|
+
html string.
|
48
|
+
|
49
|
+
Technically, only the +Serializer+ is necessary. The +input+
|
50
|
+
and +tag+ methods return +Input+ and +Tag+ objects. These objects
|
51
|
+
both have +to_s+ defined to call the appropriate +Serializer+ with
|
52
|
+
themselves. The +Serializer+ calls the appropriate +Formatter+ if
|
53
|
+
it encounters an +Input+ instance, and attempts to serialize the
|
54
|
+
output of that (which is usually a +Tag+ instance). It is up to
|
55
|
+
the +Formatter+ to call the +Labeler+ and/or +ErrorHandler+ (if
|
56
|
+
necessary) and the +Wrapper+.
|
57
|
+
|
58
|
+
There is also an +InputsWrapper+ transformer, that is called by
|
59
|
+
<tt>Forme::Form#inputs</tt>. It's used to wrap up a group of
|
60
|
+
related options (in a fieldset by default).
|
61
|
+
|
62
|
+
The <tt>Forme::Form</tt> object takes the 6 transformers as options (:formatter,
|
63
|
+
:labeler, :error_handler, :wrapper, :inputs_wrapper, and :serializer), all of which
|
64
|
+
should be objects responding to +call+ (so you can use +Proc+s) or be symbols
|
65
|
+
registered with the library using <tt>Forme.register_transformer</tt>:
|
66
|
+
|
67
|
+
Forme.register_transformer(:wrapper, :p){|t| t.tag(:p, {}, t)}
|
68
|
+
|
69
|
+
Most of the transformers can be overridden on a per instance basis by
|
70
|
+
passing the appopriate option to +input+ or +inputs+:
|
71
|
+
|
72
|
+
f.input(:name, :wrapper=>:p)
|
13
73
|
|
14
|
-
= Demo Site
|
15
74
|
|
16
|
-
|
17
|
-
|
18
|
-
= Documentation Site
|
75
|
+
= Installation
|
19
76
|
|
20
|
-
|
77
|
+
gem install forme
|
21
78
|
|
22
|
-
=
|
79
|
+
= Links
|
23
80
|
|
24
|
-
|
81
|
+
Demo Site :: http://forme-demo.jeremyevans.net
|
82
|
+
RDoc :: http://forme.jeremyevans.net
|
83
|
+
Source :: https://github.com/jeremyevans/forme
|
84
|
+
IRC :: irc://irc.freenode.net/forme
|
85
|
+
Google Group :: https://groups.google.com/forum/#!forum/ruby-forme
|
86
|
+
Bug Tracker :: https://github.com/jeremyevans/forme/issues
|
25
87
|
|
26
88
|
= Basic Usage
|
27
89
|
|
@@ -43,7 +105,7 @@ the entire form based on the object.
|
|
43
105
|
|
44
106
|
If the object doesn't respond to +forme_input+, it falls back to creating text fields
|
45
107
|
with the name and id set to the field name and the value set by calling the given method
|
46
|
-
on the object.
|
108
|
+
on the object (or using #[] if the object is a hash).
|
47
109
|
|
48
110
|
f = Forme::Form.new([:foo])
|
49
111
|
f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
|
@@ -57,12 +119,14 @@ Forme comes with a DSL:
|
|
57
119
|
f.tag(:fieldset) do
|
58
120
|
f.input(:textarea, :name=>'baz')
|
59
121
|
end
|
122
|
+
f.button('Update')
|
60
123
|
end
|
61
124
|
# <form action="/foo">
|
62
125
|
# <input name="bar" type="text"/>
|
63
126
|
# <fieldset>
|
64
127
|
# <textarea name="baz"></textarea>
|
65
128
|
# </fieldset>
|
129
|
+
# <input type="submit" value="Update"/>
|
66
130
|
# </form>
|
67
131
|
|
68
132
|
You can wrap up multiple inputs with the <tt>:inputs</tt> method:
|
@@ -82,6 +146,541 @@ You can even do everything in a single method call:
|
|
82
146
|
Forme.form({:action=>'/foo'},
|
83
147
|
:inputs=>[[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
|
84
148
|
|
149
|
+
= Forme::Form Creation
|
150
|
+
|
151
|
+
As shown above, the general way to create Forme::Form instances is via the Forme.form method.
|
152
|
+
This method takes up to 3 arguments, and yields the Forme::Form object to the block (if given).
|
153
|
+
Here are the argument styles that you can use for Forme.form.
|
154
|
+
|
155
|
+
No args :: Creates a +Form+ object with no options and not associated
|
156
|
+
to an +obj+, and with no attributes in the opening tag.
|
157
|
+
1 hash arg :: Treated as opening form tag attributes, creating a
|
158
|
+
+Form+ object with no options.
|
159
|
+
1 non-hash arg :: Treated as the +Form+'s +obj+, with empty options
|
160
|
+
and no attributes in the opening tag.
|
161
|
+
2 hash args :: First hash is opening attributes, second hash is +Form+
|
162
|
+
options.
|
163
|
+
1 non-hash arg, 1-2 hash args :: First argument is +Form+'s obj, second is
|
164
|
+
opening attributes, third if provided is
|
165
|
+
+Form+'s options.
|
166
|
+
|
167
|
+
Examples:
|
168
|
+
|
169
|
+
# No arguments
|
170
|
+
Forme.form
|
171
|
+
|
172
|
+
# 1 hash argument (attributes)
|
173
|
+
Forme.form(:action=>'/foo')
|
174
|
+
|
175
|
+
# 1 non-hash argument (a reference object used when building the form)
|
176
|
+
Forme.form(Album[1])
|
177
|
+
|
178
|
+
# 2 hash arguments (attributes, and options)
|
179
|
+
Forme.form({:action=>'/foo'}, :values=>params)
|
180
|
+
|
181
|
+
# 1 non-hash argument, 1-2 hash arguments (ref obj, attributes, options)
|
182
|
+
Forme.form(Album[1], :action=>'/foo')
|
183
|
+
Forme.form(Album[1], {:action=>'/foo'}, :values=>params)
|
184
|
+
|
185
|
+
If you want a Forme::Form instance where the reference object is a Hash, then you need to pass the hash object using the :obj option:
|
186
|
+
|
187
|
+
Forme.form({:action=>'/foo'}, :obj=>{:foo=>'bar'})
|
188
|
+
|
189
|
+
You can also create Forme::Form objects the normal ruby way using Forme::Form#new. The
|
190
|
+
difference between Forme::Form#new and Forme.form is that Forme.form includes the enclosing
|
191
|
+
<form> tag, where Forme::Form#new does not. Because of this, Forme::Form does not accept
|
192
|
+
a hash of <form> tag attributes, so it has the following API:
|
193
|
+
|
194
|
+
# No arguments
|
195
|
+
Forme::Form.new
|
196
|
+
|
197
|
+
# 1 hash argument
|
198
|
+
Forme::Form.new(:values=>params)
|
199
|
+
|
200
|
+
# 1 non-hash argument
|
201
|
+
Forme::Form.new(Album[1])
|
202
|
+
|
203
|
+
# 1 non-hash argument, 1-2 hash arguments
|
204
|
+
Forme::Form.new(Album[1], :values=>params)
|
205
|
+
|
206
|
+
= Forme::Form Methods
|
207
|
+
|
208
|
+
== form
|
209
|
+
|
210
|
+
If you create a Form via Forme::Forme#new, you can use the form method to create a form tag:
|
211
|
+
|
212
|
+
f = Forme::Form.new
|
213
|
+
f.form(:action=>'/foo')
|
214
|
+
|
215
|
+
This is what Forme.form uses internally to create the <form> tag
|
216
|
+
|
217
|
+
== input
|
218
|
+
|
219
|
+
This adds an input to the form. If the form has an associated object, and that
|
220
|
+
object responds to +forme_input+, calls forme_input with the argument and options:
|
221
|
+
|
222
|
+
f = Forme::Form.new(obj)
|
223
|
+
f.input(:field) # '<input id="obj_field" name="obj[field]" type="text" value="foo"/>'
|
224
|
+
|
225
|
+
If the form has an associated object, and that object does not respond to +forme_iuput+,
|
226
|
+
calls the method on the object (or uses [] if the object is a hash), and uses the result
|
227
|
+
as the value:
|
228
|
+
|
229
|
+
f = Forme::Form.new([:foo])
|
230
|
+
f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
|
231
|
+
|
232
|
+
If the form does not have an assocaited object, uses the first argument as the input
|
233
|
+
type:
|
234
|
+
|
235
|
+
f = Forme::Form.new
|
236
|
+
f.input(:text) # '<input type="text" />'
|
237
|
+
|
238
|
+
The second argument is an options hash. See below for the supported input types and options.
|
239
|
+
|
240
|
+
== tag
|
241
|
+
|
242
|
+
This adds a tag to the form. If a block is given, yields to the block, and tags and inputs
|
243
|
+
inside the block are placed inside the tag. The first argument is the type of tag to create,
|
244
|
+
and the second argument if given should be a hash of tag attributes. This allows you to nest
|
245
|
+
inputs inside tags:
|
246
|
+
|
247
|
+
Forme.form do |f|
|
248
|
+
f.tag(:span, :class="foo") do
|
249
|
+
f.input(:text)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
Which results in a form similar to the following:
|
254
|
+
|
255
|
+
<form>
|
256
|
+
<span class="foo">
|
257
|
+
<input type="text"/>
|
258
|
+
</span>
|
259
|
+
</form>
|
260
|
+
|
261
|
+
== inputs
|
262
|
+
|
263
|
+
This wraps multiple inputs in a tag (it uses the inputs_wrapper transformer discussed below,
|
264
|
+
so it uses a fieldset by default). You can give the inputs to add as an enumerable argument:
|
265
|
+
|
266
|
+
f.inputs([:textarea, [:text, :value=>'a']])
|
267
|
+
# <fieldset>
|
268
|
+
# <textarea></textarea>
|
269
|
+
# <input type="text" value="a"/>
|
270
|
+
# </fieldset>
|
271
|
+
|
272
|
+
You can also provide a block:
|
273
|
+
|
274
|
+
f.inputs([:textarea]) do
|
275
|
+
f.input(:text, :value=>'a')
|
276
|
+
end
|
277
|
+
|
278
|
+
Any options given are passed to the inputs_wrapper (so you can use options such as :legend
|
279
|
+
to set a legend for the fieldset), and also to the the with_opts (so you can use options
|
280
|
+
such as :wrapper to modify the default wrapper transformer for inputs inside the block).
|
281
|
+
There is also one option specific to the inputs method:
|
282
|
+
|
283
|
+
:nested_inputs_wrapper :: Sets the default inputs_wrapper to use for calls to inputs inside
|
284
|
+
the block. The reason for this option is that :inputs_wrapper
|
285
|
+
option affects the current call to inputs, so if you want to
|
286
|
+
use a different inputs_wrapper for nested calls, you need this option.
|
287
|
+
|
288
|
+
== button
|
289
|
+
|
290
|
+
This adds a submit input to the form:
|
291
|
+
|
292
|
+
f.button
|
293
|
+
# <input type="submit"/>
|
294
|
+
|
295
|
+
It can be called with a string to provide a value for the button:
|
296
|
+
|
297
|
+
f.button('Search')
|
298
|
+
# <input type="submit" value="Search"/>
|
299
|
+
|
300
|
+
It can be called with a hash to provide options for the submit input:
|
301
|
+
|
302
|
+
f.button(:value=>'Search', :class=>'btn')
|
303
|
+
# <input class="btn" type="submit" value="Search"/>
|
304
|
+
|
305
|
+
== with_opts
|
306
|
+
|
307
|
+
This requires a block, and modifies the Form's options inside the block,
|
308
|
+
restoring the options when the block returns:
|
309
|
+
|
310
|
+
f.input(:text)
|
311
|
+
# <input type="text"/>
|
312
|
+
f.with_opts(:wrapper=>:li) do
|
313
|
+
f.input(:text)
|
314
|
+
end
|
315
|
+
# <li><input type="text"/></li>
|
316
|
+
|
317
|
+
This supports most options you can provide to the Form, but not all.
|
318
|
+
|
319
|
+
== with_obj
|
320
|
+
|
321
|
+
This uses with_opts to change the Form's object temporarily, but it
|
322
|
+
yields the object to the block, and also supports appending to the
|
323
|
+
existing namespaces:
|
324
|
+
|
325
|
+
Forme.form([:foo], :namespace=>'a') do |f|
|
326
|
+
f.input(:first)
|
327
|
+
# <input id="a_first" name="a[first]" type="text" value="foo"/>
|
328
|
+
f.with_obj(['foobar'], 'b') do |o|
|
329
|
+
f.input(:first, :size=>o.first.size)
|
330
|
+
# <input id="a_b_first" name="a[b][first]" size="6" type="text" value="foobar"/>
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
== each_obj
|
335
|
+
|
336
|
+
This allows you to provide an object-yielding enumerable. Forme will call with_obj with
|
337
|
+
each object in the enumerable. It yields each object as well as the index of the
|
338
|
+
object in the enumerable, and includes the index in the namespace:
|
339
|
+
|
340
|
+
objectlist = ['foobar', ['good']]
|
341
|
+
Forme.form([:foo], :namespace=>'a') do |f|
|
342
|
+
f.each_obj(objectlist, 'b') do |o, i|
|
343
|
+
f.input(:first, :size=>10+i)
|
344
|
+
end
|
345
|
+
# <input id="a_b_0_first" name="a[b][0][first]" size="10" type="text" value="foobar"/>
|
346
|
+
# <input id="a_b_1_first" name="a[b][1][first]" size="11" type="text" value="good"/>
|
347
|
+
end
|
348
|
+
|
349
|
+
= Sequel Support
|
350
|
+
|
351
|
+
Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to enable), that makes
|
352
|
+
Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
|
353
|
+
|
354
|
+
== Basics
|
355
|
+
|
356
|
+
The Sequel support handles inputs based on database columns, and automatically handles labels and errors.
|
357
|
+
|
358
|
+
Forme.form(Album[1], :action=>'/foo') do |f|
|
359
|
+
f.input :name
|
360
|
+
f.input :copies_sold
|
361
|
+
end
|
362
|
+
|
363
|
+
This will create a form similar to:
|
364
|
+
|
365
|
+
<form action="/foo" method="post">
|
366
|
+
<label>Name: <input id="album_name" name="album[name]" type="text" value="Rising Force"/></label>
|
367
|
+
<label>Copies Sold: <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/></label>
|
368
|
+
</form>
|
369
|
+
|
370
|
+
The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
|
371
|
+
+validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
|
372
|
+
based on the format, numericality, and length validations.
|
373
|
+
|
374
|
+
== specialized input options
|
375
|
+
|
376
|
+
In addition to the default Forme options, the Sequel support includes, for specific column types,
|
377
|
+
these additional options to the #input method:
|
378
|
+
.
|
379
|
+
|
380
|
+
=== boolean
|
381
|
+
|
382
|
+
:as :: Can be set to :select, :radio, or :checkbox. :select will use a select input with three
|
383
|
+
options, a blank option, a true option, and a false option. :radio will use two radio
|
384
|
+
inputs, one for true and one for false. :checkbox will use a single checkbox input.
|
385
|
+
By default, uses :select if NULL values are allowed and the option is not required, and
|
386
|
+
:checkbox otherwise.
|
387
|
+
:false_label :: The value to use for the false label, 'No' by default.
|
388
|
+
:false_value :: The value to use for the false input, 'f' by default.
|
389
|
+
:true_label :: The value to use for the true label, 'Yes' by default.
|
390
|
+
:true_value :: The value to use for the true input, 't' by default.
|
391
|
+
|
392
|
+
== string
|
393
|
+
|
394
|
+
:as :: Can be set to :textarea to use a textarea input. You can use the usual attributes hash or a stylesheet to
|
395
|
+
control the size of the textarea.
|
396
|
+
|
397
|
+
== associations
|
398
|
+
|
399
|
+
The Sequel support also handles associations, allowing you to change which objects are associated
|
400
|
+
to the current object.
|
401
|
+
|
402
|
+
Forme.form(Album[1], :action=>'/foo') do |f|
|
403
|
+
f.input :name
|
404
|
+
f.input :artist
|
405
|
+
f.input :tags, :as=>:checkbox
|
406
|
+
end
|
407
|
+
|
408
|
+
This will create a form similar to:
|
409
|
+
|
410
|
+
<form action="/foo" method="post">
|
411
|
+
<label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
|
412
|
+
<label>Artist: <select id="album_artist_id" name="album[artist_id]">
|
413
|
+
<option selected="selected" value="1">Elvis Presley</option>
|
414
|
+
<option value="2">The Beatles</option>
|
415
|
+
<option value="3">The Monkeys</option>
|
416
|
+
</select></label>
|
417
|
+
<span class="label">Tags:
|
418
|
+
<label><input checked="checked" id="album_tag_pks_1" name="album[tag_pks][]" type="checkbox" value="1"/> Rock and Roll</label>
|
419
|
+
<label><input id="album_tag_pks_2" name="album[tag_pks][]" type="checkbox" value="2"/> Blues</label>
|
420
|
+
<label><input id="album_tag_pks_3" name="album[tag_pks][]" type="checkbox" value="3"/> Country</label>
|
421
|
+
</span>
|
422
|
+
</form>
|
423
|
+
|
424
|
+
For one_to_many and many_to_many associations, you will probably want to use the
|
425
|
+
+association_pks+ plugin that ships with Sequel.
|
426
|
+
|
427
|
+
association input options:
|
428
|
+
|
429
|
+
:as :: For many_to_one associations, set to :radio to use a series of radio buttons instead
|
430
|
+
a select input. For one_to_many and many_to_many associations, set to :checkbox to
|
431
|
+
use a series of checkboxes instead of a multiple select input.
|
432
|
+
:dataset :: If a Dataset, uses the dataset to retrieve the options. If a Proc or Method,
|
433
|
+
calls the proc or method with the default dataset, and should return a modified
|
434
|
+
dataset to use.
|
435
|
+
:options :: Specify the options to use for the input(s), instead of querying the database.
|
436
|
+
:name_method :: If a String or Symbol, treats it as a method name and calls it on each object
|
437
|
+
returned by the dataset to get the text to use for the option. If not given,
|
438
|
+
tries the following method names in order: :forme_name, :name, :title, :number.
|
439
|
+
If given and not a String or Symbol, a callable object is assumed, and the value
|
440
|
+
is called with each object and should return the text to use for the option.
|
441
|
+
|
442
|
+
== subform
|
443
|
+
|
444
|
+
The Sequel support includes a method called subform, which can handle nested_attributes:
|
445
|
+
|
446
|
+
Forme.form(Album[1], :action=>'/foo') do |f|
|
447
|
+
|
448
|
+
f.input :name
|
449
|
+
|
450
|
+
f.subform :artist do
|
451
|
+
f.input :name
|
452
|
+
end
|
453
|
+
|
454
|
+
f.subform :tracks do
|
455
|
+
f.input :number
|
456
|
+
f.input :name
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
This adds an input for editing the artist's name after the album's inputs, as well as
|
462
|
+
inputs for editing the number and name for all of the tracks in the album, creating a
|
463
|
+
form similar to:
|
464
|
+
|
465
|
+
<form action="/foo" method="post">
|
466
|
+
|
467
|
+
<label>Name: <input id="album_name" name="album[name]" type="text" value="Blue Hawaii"/></label>
|
468
|
+
|
469
|
+
<input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="1"/>
|
470
|
+
<fieldset class="inputs"><legend>Artist</legend>
|
471
|
+
<label>Name: <input id="album_artist_attributes_name" name="album[artist_attributes][name]" type="text" value="Elvis Presley"/></label>
|
472
|
+
</fieldset>
|
473
|
+
|
474
|
+
<input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/>
|
475
|
+
<fieldset class="inputs"><legend>Track #1</legend>
|
476
|
+
<label>Number: <input id="album_tracks_attributes_0_number" name="album[tracks_attributes][0][number]" type="number" value="1"/></label>
|
477
|
+
<label>Name: <input id="album_tracks_attributes_0_name" name="album[tracks_attributes][0][name]" type="text" value="Blue Hawaii"/></label>
|
478
|
+
</fieldset>
|
479
|
+
<input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/>
|
480
|
+
<fieldset class="inputs"><legend>Track #2</legend>
|
481
|
+
<label>Number: <input id="album_tracks_attributes_1_number" name="album[tracks_attributes][1][number]" type="number" value="2"/></label>
|
482
|
+
<label>Name: <input id="album_tracks_attributes_1_name" name="album[tracks_attributes][1][name]" type="text" value="Almost Always True"/></label>
|
483
|
+
</fieldset>
|
484
|
+
|
485
|
+
</form>
|
486
|
+
|
487
|
+
<em>Note: blank lines added for clarity; they would not appear in the actual output</em>
|
488
|
+
|
489
|
+
subform options:
|
490
|
+
|
491
|
+
:inputs :: Automatically call +inputs+ with the given values. Using
|
492
|
+
this, it is not required to pass a block to the method,
|
493
|
+
though it will still work if you do.
|
494
|
+
:legend :: Overrides the default :legend used (which is based on the
|
495
|
+
association name). You can also use a proc as the value,
|
496
|
+
which will called with each associated object (and the position
|
497
|
+
in the associated object already for *_to_many associations),
|
498
|
+
and should return the legend string to use for that object.
|
499
|
+
:grid :: Sets up a table with one row per associated object, and
|
500
|
+
one column per field.
|
501
|
+
:labels :: When using the :grid option, override the labels that would
|
502
|
+
be created via the :inputs option. If you are not providing
|
503
|
+
an :inputs option or are using a block with additional inputs,
|
504
|
+
you should specify this option.
|
505
|
+
|
506
|
+
= Sinatra Support
|
507
|
+
|
508
|
+
Forme ships with a Sinatra extension that you can get by <tt>require "forme/sinatra"</tt> and using
|
509
|
+
<tt>helpers Forme::Sinatra::ERB</tt> in your Sinatra::Base subclass. It allows you to use the
|
510
|
+
following API in your Sinatra ERB forms:
|
511
|
+
|
512
|
+
<% form(@obj, :action=>'/foo') do |f| %>
|
513
|
+
<%= f.input(:field) %>
|
514
|
+
<% f.tag(:fieldset) do %>
|
515
|
+
<%= f.input(:field_two) %>
|
516
|
+
<% end %>
|
517
|
+
<% end %>
|
518
|
+
|
519
|
+
This example is for ERB/Erubis. Other Sinatra template libraries work differently and
|
520
|
+
do not support this integration.
|
521
|
+
|
522
|
+
= Rails Support
|
523
|
+
|
524
|
+
Forme ships with a Rails extension that you can get by <tt>require "forme/rails"</tt> and using
|
525
|
+
<tt>helpers Forme::Rails::ERB</tt> in your controller. If allows you to use the following API
|
526
|
+
in your Rails forms:
|
527
|
+
|
528
|
+
<%= forme(@obj, :action=>'/foo') do |f| %>
|
529
|
+
<%= f.input(:field) %>
|
530
|
+
<%= f.tag(:fieldset) do %>
|
531
|
+
<%= f.input(:field_two) %>
|
532
|
+
<% end %>
|
533
|
+
<% end %>
|
534
|
+
|
535
|
+
This has been tested on Rails 3.2-4.1, but should hopefully work on Rails 3.0+.
|
536
|
+
|
537
|
+
= Input Types and Options
|
538
|
+
|
539
|
+
These are the types and options supported by Forme::Input objects, usually
|
540
|
+
created via Forme::Form#input:
|
541
|
+
|
542
|
+
== General Options
|
543
|
+
|
544
|
+
These options are supported by all of the input types:
|
545
|
+
|
546
|
+
:attr :: The attributes hash to use for the given tag, takes precedence over
|
547
|
+
other options that set attributes.
|
548
|
+
:autofocus :: Set the autofocus attribute if true
|
549
|
+
:class :: A class to use. Unlike other options, this is combined with the
|
550
|
+
classes set in the :attr hash.
|
551
|
+
:data :: A hash of data-* attributes for the resulting tag. Keys in this hash
|
552
|
+
will have attributes created with data- prepended to the attribute name.
|
553
|
+
:disabled :: Set the disabled attribute if true
|
554
|
+
:error :: Set an error message, invoking the error_handler
|
555
|
+
:error_handler :: Set a custom error_handler, overriding the form's default
|
556
|
+
:id :: The id attribute to use
|
557
|
+
:key :: The base to use for the name and id attributes, based on the current
|
558
|
+
namespace for the form.
|
559
|
+
:label :: Set a label, invoking the labeler
|
560
|
+
:labeler :: Set a custom labeler, overriding the form's default
|
561
|
+
:name :: The name attribute to use
|
562
|
+
:placeholder :: The placeholder attribute to use
|
563
|
+
:required :: Set the required attribute if true
|
564
|
+
:value :: The value attribute to use for input tags, the content of the textarea
|
565
|
+
for textarea tags, or the selected option(s) for select tags.
|
566
|
+
:wrapper :: Set a custom wrapper, overriding the form's default
|
567
|
+
|
568
|
+
== Input Types
|
569
|
+
|
570
|
+
=== :checkbox
|
571
|
+
|
572
|
+
Creates an input tag with type checkbox, as well as a hidden input tag. Options:
|
573
|
+
|
574
|
+
:checked :: Mark the checkbox as checked.
|
575
|
+
:hidden_value :: The value to use for the hidden input tag.
|
576
|
+
:no_hidden :: Don't create a hidden input tag.
|
577
|
+
|
578
|
+
=== :radio
|
579
|
+
|
580
|
+
Creates an input tag with type radio. Options:
|
581
|
+
|
582
|
+
:checked :: Mark the radio button as checked.
|
583
|
+
|
584
|
+
=== :date
|
585
|
+
|
586
|
+
By default, creates an input tag with type date. With the :as=>:select option, creates
|
587
|
+
3 select boxes, one for the year, month, and day. Options:
|
588
|
+
|
589
|
+
:as :: When value is :select, uses 3 select boxes.
|
590
|
+
|
591
|
+
=== :datetime
|
592
|
+
|
593
|
+
By default, creates an input tag with type datetime. With the :as=>:select option, creates
|
594
|
+
6 select boxes, one for the year, month, day, hour, minute, and second. Options:
|
595
|
+
|
596
|
+
:as :: When value is :select, uses 6 select boxes.
|
597
|
+
|
598
|
+
=== :select
|
599
|
+
|
600
|
+
Creates a select tag, containing option tags specified by the :options option. Options:
|
601
|
+
|
602
|
+
:add_blank :: Add a blank option if true. If the value is a string,
|
603
|
+
use it as the text content of the blank option. The default value can be
|
604
|
+
set with Forme.default_add_blank_prompt, and defaults to the empty string.
|
605
|
+
:multiple :: Creates a multiple select box.
|
606
|
+
:options :: an array of options used for creating option tags.
|
607
|
+
If the :text_method and :value_method are not given and the entry is an
|
608
|
+
array, uses the first entry of the array as the text of the option, and
|
609
|
+
the second entry of the array as the value of the option.
|
610
|
+
:selected :: The value that should be selected. Any options that are equal to
|
611
|
+
this value (or included in this value if a multiple select box),
|
612
|
+
are set to selected.
|
613
|
+
:text_method :: If set, each entry in the array has this option called on
|
614
|
+
it to get the text of the object.
|
615
|
+
:value :: Same as :selected, but has lower priority.
|
616
|
+
:value_method :: If set (and :text_method is set), each entry in the array
|
617
|
+
has this method called on it to get the value of the option.
|
618
|
+
|
619
|
+
=== :checkboxset
|
620
|
+
|
621
|
+
Creates a set of checkbox inputs all using the same name. Supports the same options
|
622
|
+
as the select type, except that the :multiple option is assumed to be true.
|
623
|
+
|
624
|
+
=== :radioset
|
625
|
+
|
626
|
+
Creates a set of radio buttons all using the same name. Supports the same options
|
627
|
+
as the select type.
|
628
|
+
|
629
|
+
=== :textarea
|
630
|
+
|
631
|
+
Creates a textarea tag. Options:
|
632
|
+
|
633
|
+
:cols :: The number of columns in the text area.
|
634
|
+
:rows :: The number of rows in the text area.
|
635
|
+
|
636
|
+
== all others
|
637
|
+
|
638
|
+
Creates an input tag with the given type. This makes it easy to use inputs such
|
639
|
+
as text and password, as well as newer HTML5 inputs such as number or email. Options:
|
640
|
+
|
641
|
+
:size :: Uses the size attribute on the tag
|
642
|
+
:maxlength :: Use the maxlength attribute on the tag
|
643
|
+
|
644
|
+
== Form options
|
645
|
+
|
646
|
+
These are the options supported by Forme::Form object, mostly used to set
|
647
|
+
the defaults for Inputs created via the form:
|
648
|
+
|
649
|
+
:config :: The configuration to use, which automatically sets defaults
|
650
|
+
for the transformers to use.
|
651
|
+
:error_handler :: Sets the default error_handler for the form's inputs
|
652
|
+
:formatter :: Sets the default formatter for the form's inputs
|
653
|
+
:hidden_tags :: Sets the hidden tags to automatically add to this form, see below.
|
654
|
+
:input_defaults :: Sets the default options for each input type. This should
|
655
|
+
be a hash with input type keys, where the values are the
|
656
|
+
hash of default options to use for the input type.
|
657
|
+
:inputs_wrapper :: Sets the default inputs_wrapper for the form
|
658
|
+
:labeler :: Sets the default labeler for the form's inputs
|
659
|
+
:namespace :: Sets the default namespace(s) to use for the form. Namespacing
|
660
|
+
will automatically create namespaced name and id attributes for
|
661
|
+
inputs that use the :key option.
|
662
|
+
:obj :: Sets the default +obj+ for the form's inputs.
|
663
|
+
:serializer :: Sets the serializer for the form
|
664
|
+
:values :: The values from a previous form submission, used to set default
|
665
|
+
values for inputs when the inputs use the :key option.
|
666
|
+
:wrapper :: Sets the default wrapper for the form's inputs
|
667
|
+
|
668
|
+
For forms created by Forme.form, the following options are supported:
|
669
|
+
|
670
|
+
:inputs :: An array of inputs to create inside the form, before yielding
|
671
|
+
to the block.
|
672
|
+
:button :: A button to add to the form, after yielding to the block.
|
673
|
+
|
674
|
+
=== :hidden_tags
|
675
|
+
|
676
|
+
This should be an array, where elements are one of the following types:
|
677
|
+
|
678
|
+
String, Array, Forme::Tag :: Added directly as a child of the form tag.
|
679
|
+
Hash :: Adds a hidden tag for each entry, with keys as the name of the hidden
|
680
|
+
tag and values as the value of the hidden tag.
|
681
|
+
Proc :: Will be called with the form tag object, and should return an instance
|
682
|
+
of one of the handled types (or nil to not add a tag).
|
683
|
+
|
85
684
|
= Basic Design
|
86
685
|
|
87
686
|
Internally, Forme builds an abstract syntax tree of objects that
|
@@ -142,23 +741,52 @@ Forme ships with a bunch of built-in transformers that you can use:
|
|
142
741
|
:default :: uses implicit labels, where the tag is a child of the label tag
|
143
742
|
:explicit :: uses explicit labels with the for attribute, where tag is a sibling of the label tag
|
144
743
|
|
744
|
+
Both of these respect the following options:
|
745
|
+
|
746
|
+
:label_position :: Can be set to :before or :after to place the label before or after the the input.
|
747
|
+
:label_attr :: A hash of attributes to use for the label tag
|
748
|
+
|
145
749
|
=== +wrapper+
|
146
750
|
|
147
751
|
:default :: returns tag without wrapping
|
752
|
+
:div :: wraps tag in div tag
|
753
|
+
:fieldset_ol :: same as :li, but also sets +inputs_wrapper+ to :fieldset_ol
|
148
754
|
:li :: wraps tag in li tag
|
755
|
+
:ol :: same as :li, but also sets +inputs_wrapper+ to :ol
|
149
756
|
:p :: wraps tag in p tag
|
150
|
-
:div :: wraps tag in div tag
|
151
757
|
:span :: wraps tag in span tag
|
758
|
+
:table :: same as :trtd, but also sets +inputs_wrapper+ to :table
|
759
|
+
:td :: wraps tag in a td tag
|
760
|
+
:tr :: same as :td, but also sets +inputs_wrapper+ to :tr
|
152
761
|
:trtd :: wraps tag in a tr tag with a td for the label and a td for the tag, useful for lining up
|
153
762
|
inputs with the :explicit labeler without CSS
|
154
763
|
|
764
|
+
All of these except for :default respect the following options:
|
765
|
+
|
766
|
+
:wrapper_attr :: A hash of attributes to use for the wrapping tag.
|
767
|
+
|
155
768
|
=== +inputs_wrapper+
|
156
769
|
|
157
770
|
:default :: uses a fieldset to wrap inputs
|
158
|
-
:ol :: uses an ol tag to wrap inputs, useful with :li wrapper
|
159
771
|
:div :: uses a div tag to wrap inputs
|
160
772
|
:fieldset_ol :: use both a fieldset and an ol tag to wrap inputs
|
773
|
+
:ol :: uses an ol tag to wrap inputs, useful with :li wrapper
|
161
774
|
:table :: uses a table tag to wrap inputs, useful with :trtd wrapper
|
775
|
+
:tr :: uses a tr tag to wrap inputs, useful with :td wrapper
|
776
|
+
|
777
|
+
All of these support the following options:
|
778
|
+
|
779
|
+
:attr :: A hash of attributes to use for the wrapping tag.
|
780
|
+
|
781
|
+
The :default, :fieldset_ol, and :table inputs_wrappers support the following options:
|
782
|
+
|
783
|
+
:legend :: A text description for the inputs, using the legend tag for fieldsets and
|
784
|
+
the caption tag for a table.
|
785
|
+
:legend_attr :: A hash of attributes for the legend/caption tag.
|
786
|
+
|
787
|
+
The :table inputs_wrapper also supports the following options:
|
788
|
+
|
789
|
+
:labels :: An array of labels, used to setup a row of table headers with the labels.
|
162
790
|
|
163
791
|
== Configurations
|
164
792
|
|
@@ -184,61 +812,6 @@ You can mark a configuration as the default using:
|
|
184
812
|
|
185
813
|
Forme.default_config = :mine
|
186
814
|
|
187
|
-
= Sequel Support
|
188
|
-
|
189
|
-
Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to enable), that makes
|
190
|
-
Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
|
191
|
-
|
192
|
-
It deals with inputs based on database columns, virtual columns, and associations. It also handles
|
193
|
-
nested associations using the +subform+ method:
|
194
|
-
|
195
|
-
Forme.form(Album[1], :action=>'/foo') do |f|
|
196
|
-
f.inputs([:name, :copies_sold, :tags]) do
|
197
|
-
f.subform(:artist, :inputs=>[:name])
|
198
|
-
f.subform(:tracks, :inputs=>[:number, :name])
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
For many_to_one associations, you can use the <tt>:as=>:radio</tt> option to use a series of radio buttons,
|
203
|
-
and for one_to_many and many_to_many associations, you can use the <tt>:as=>:checkbox</tt> option to use a
|
204
|
-
series of checkboxes. For one_to_many and many_to_many associations, you will probably want to use the
|
205
|
-
+association_pks+ plugin that ships with Sequel.
|
206
|
-
|
207
|
-
The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
|
208
|
-
+validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
|
209
|
-
based on the format, numericality, and length validations.
|
210
|
-
|
211
|
-
= Sinatra Support
|
212
|
-
|
213
|
-
Forme ships with a Sinatra extension that you can get by <tt>require "forme/sinatra"</tt> and using
|
214
|
-
<tt>helpers Forme::Sinatra::ERB</tt> in your Sinatra::Base subclass. It allows you to use the
|
215
|
-
following API in your Sinatra ERB forms:
|
216
|
-
|
217
|
-
<% form(@obj, :action=>'/foo') do |f| %>
|
218
|
-
<%= f.input(:field) %>
|
219
|
-
<% f.tag(:fieldset) do %>
|
220
|
-
<%= f.input(:field_two) %>
|
221
|
-
<% end %>
|
222
|
-
<% end %>
|
223
|
-
|
224
|
-
This example is for ERB/Erubis. Other Sinatra template libraries work differently and
|
225
|
-
probably do not support this integration.
|
226
|
-
|
227
|
-
= Rails Support
|
228
|
-
|
229
|
-
Forme ships with a Rails extension that you can get by <tt>require "forme/rails"</tt> and using
|
230
|
-
<tt>helpers Forme::Rails::ERB</tt> in your controller. If allows you to use the following API
|
231
|
-
in your Rails forms:
|
232
|
-
|
233
|
-
<%= forme(@obj, :action=>'/foo') do |f| %>
|
234
|
-
<%= f.input(:field) %>
|
235
|
-
<%= f.tag(:fieldset) do %>
|
236
|
-
<%= f.input(:field_two) %>
|
237
|
-
<% end %>
|
238
|
-
<% end %>
|
239
|
-
|
240
|
-
This has been tested on Rails 3.2, but should hopefully work on Rails 3.0+.
|
241
|
-
|
242
815
|
= Other Similar Projects
|
243
816
|
|
244
817
|
All of these have external dependencies:
|
@@ -248,7 +821,11 @@ All of these have external dependencies:
|
|
248
821
|
3. simple_form
|
249
822
|
4. padrino-helpers
|
250
823
|
|
251
|
-
Forme's
|
824
|
+
Forme's DSL draws a lot of inspiration from both Formtastic and simple_form.
|
825
|
+
|
826
|
+
= License
|
827
|
+
|
828
|
+
MIT
|
252
829
|
|
253
830
|
= Author
|
254
831
|
|