forme 0.9.2 → 0.10.0
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/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
|
|