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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 631cc2f4948e4efca43764c957b89a191cf42183
4
- data.tar.gz: e4b438e00bb85b76207c4c010c2346f66e0fbf57
3
+ metadata.gz: 610c1c28c2ed6fc3c4f36d520c4e67fea4fa9c1f
4
+ data.tar.gz: 7bb48306b738007c7c40c0673ad964c94f1e4c0d
5
5
  SHA512:
6
- metadata.gz: 1406aec8ddec78e1b8fc25ae0d9812d4518d9aae7c65bb2daa27dff300970dbaff4b71c96d0254b7638166995056ddede4d316b287d59c71b6e410cc314daccc
7
- data.tar.gz: 3ae282714c78f13d8115caacdf06d4f8037123ee2ece35ea752a31a6fe05e9124eb29aa5162fb785e1f35b88a892a50cb95e86324b62171e24bf1e1b51d5dad0
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2013 Jeremy Evans
1
+ Copyright (c) 2011-2014 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
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
- = Installation
11
-
12
- sudo gem install forme
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
- A demo site is available at http://forme-demo.jeremyevans.net
17
-
18
- = Documentation Site
75
+ = Installation
19
76
 
20
- RDoc Documentation is available at http://forme.jeremyevans.net
77
+ gem install forme
21
78
 
22
- = Source Code
79
+ = Links
23
80
 
24
- Source code is available on GitHub at https://github.com/jeremyevans/forme
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 API draws a lot of inspiration from both Formtastic and simple_form.
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