forme 1.9.0 → 1.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 +22 -0
- data/README.rdoc +9 -1
- data/lib/forme/bs3.rb +1 -1
- data/lib/forme/form.rb +1 -1
- data/lib/forme/transformers/error_handler.rb +46 -1
- data/lib/forme/transformers/formatter.rb +33 -35
- data/lib/forme/transformers/inputs_wrapper.rb +2 -2
- data/lib/forme/transformers/labeler.rb +19 -0
- data/lib/forme/transformers/wrapper.rb +1 -1
- data/lib/forme/version.rb +1 -1
- data/spec/forme_spec.rb +46 -14
- data/spec/roda_integration_spec.rb +9 -1
- data/spec/sequel_plugin_spec.rb +6 -6
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 581902a62cc974ce05fecf52a4b7debd41b5d89f5ba151c1c03a2f0589f15e7e
|
4
|
+
data.tar.gz: 5252e5dca95690ddf46341e443954058644f41c67e2109d7692a6dfb8c3b3ee8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39c198d2db64a06eacf30e1ed2e5af10bce818fe45f81c17ab8fcd4db7b1693afb3c2e82d013615105dd71907e96eead22104340068b04361492b853fe03da65
|
7
|
+
data.tar.gz: 33bfcf058c9ffc34f9581f3aa78e924b6764b034c56495ebaebd241eb07f5984e4330ddbab3f3a934cc77e66412e01c07decbf81bee07bb10c5d829eb00dff6f
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
=== 1.10.0 (2019-05-13)
|
2
|
+
|
3
|
+
* Make readonly formatter ignore hidden inputs (jeremyevans)
|
4
|
+
|
5
|
+
* Add :select_labels for date inputs using :as=>:select to use labels for the inputs for better accessibility (jeremyevans)
|
6
|
+
|
7
|
+
* Add :after_legend error_handler for adding error message after legend when using :legend labeler (jeremyevans)
|
8
|
+
|
9
|
+
* Add aria-describedby to all inputs with errors where possible for better accessibility (jeremyevans)
|
10
|
+
|
11
|
+
* Add aria-invalid to all inputs with errors for better accessibility (jeremyevans)
|
12
|
+
|
13
|
+
* Support :fieldset wrapper and :legend labeler, can be used for accessible radioset/checkboxset (jeremyevans)
|
14
|
+
|
15
|
+
* Support :tag_label_attr option for radioset and checkbox set for label attributes for each radio/checkbox label (jeremyevans)
|
16
|
+
|
17
|
+
* Support custom :error_handler in radioset and checkboxset inputs (jeremyevans)
|
18
|
+
|
19
|
+
* Support custom :labeler in radioset and checkboxset inputs (jeremyevans)
|
20
|
+
|
21
|
+
* Avoid calling Proc.new with an implicit block, which is deprecated starting in ruby 2.7 (jeremyevans)
|
22
|
+
|
1
23
|
=== 1.9.0 (2018-11-16)
|
2
24
|
|
3
25
|
* Automatically add maxlength attributes to text and textarea inputs in the Sequel plugin based on maximum database column length (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -822,6 +822,8 @@ creates multiple select options. Options:
|
|
822
822
|
for the select field and string to use a string
|
823
823
|
(:date default: <tt>[:year, '-', :month, '-', :day]</tt>)
|
824
824
|
(:datetime default: <tt>[:year, '-', :month, '-', :day, ' ', :hour, ':', :minute, ':', :second]</tt>)
|
825
|
+
:select_labels :: The labels to use for the select boxes. Should be a hash keyed by the
|
826
|
+
symbol used in order. By default, no labels are used.
|
825
827
|
:select_options :: The options to use for the select boxes. Should be a hash keyed by the
|
826
828
|
symbol used in order (e.g. <tt>{:year=>1970..2020}</tt>)
|
827
829
|
|
@@ -862,6 +864,7 @@ the following options:
|
|
862
864
|
|
863
865
|
:tag_wrapper :: The wrapper transformer for individual tags in the set
|
864
866
|
:tag_labeler :: The labeler transformer for individual tags in the set
|
867
|
+
:tag_label_attr :: The attributes to use for labels for individual tags in the set
|
865
868
|
|
866
869
|
=== :radioset
|
867
870
|
|
@@ -980,7 +983,9 @@ Forme ships with a bunch of built-in transformers that you can use:
|
|
980
983
|
|
981
984
|
=== +error_handler+
|
982
985
|
|
986
|
+
:after_legend :: designed for usage with :legend labeler, putting error message after legend, adding error for first input in the set
|
983
987
|
:default :: modifies tag to add an error class and adds a span with the error message
|
988
|
+
:set :: default error_handler for checkboxset and radioset inputs, that adds an error to the last input in the set
|
984
989
|
|
985
990
|
This supports the following options:
|
986
991
|
|
@@ -998,8 +1003,10 @@ This supports the following options:
|
|
998
1003
|
|
999
1004
|
:default :: uses implicit labels, where the tag is a child of the label tag
|
1000
1005
|
:explicit :: uses explicit labels with the for attribute, where tag is a sibling of the label tag
|
1006
|
+
:legend :: adds a legend before the tags, mostly useful for accessible checkboxset and radioset inputs
|
1007
|
+
:span :: default labeler for checkboxset and radioset inputs that adds a span before the tags
|
1001
1008
|
|
1002
|
-
|
1009
|
+
The :default and :explicit labelers respect the following options:
|
1003
1010
|
|
1004
1011
|
:label_position :: Can be set to :before or :after to place the label before or after the the input.
|
1005
1012
|
:label_attr :: A hash of attributes to use for the label tag
|
@@ -1008,6 +1015,7 @@ Both of these respect the following options:
|
|
1008
1015
|
|
1009
1016
|
:default :: returns tag without wrapping
|
1010
1017
|
:div :: wraps tag in div tag
|
1018
|
+
:fieldset :: wraps tags in a fieldset, mostly useful for accessible checkboxset and radioset inputs
|
1011
1019
|
:fieldset_ol :: same as :li, but also sets +inputs_wrapper+ to :fieldset_ol
|
1012
1020
|
:li :: wraps tag in li tag
|
1013
1021
|
:ol :: same as :li, but also sets +inputs_wrapper+ to :ol
|
data/lib/forme/bs3.rb
CHANGED
data/lib/forme/form.rb
CHANGED
@@ -11,10 +11,55 @@ module Forme
|
|
11
11
|
|
12
12
|
# Return tag with error message span tag after it.
|
13
13
|
def call(tag, input)
|
14
|
+
[tag, error_tag(input)]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def error_tag(input)
|
14
20
|
attr = input.opts[:error_attr]
|
15
21
|
attr = attr ? attr.dup : {}
|
16
22
|
Forme.attr_classes(attr, 'error_message')
|
17
|
-
|
23
|
+
|
24
|
+
if id = input.opts[:error_id]
|
25
|
+
unless attr['id'] || attr[:id]
|
26
|
+
attr['id'] = id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
input.tag(:span, attr, input.opts[:error])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ErrorHandler::Set < ErrorHandler
|
35
|
+
Forme.register_transformer(:error_handler, :set, new)
|
36
|
+
|
37
|
+
def call(tag, input)
|
38
|
+
return super unless last_input = input.opts[:last_input]
|
39
|
+
|
40
|
+
last_input.opts[:error] = input.opts[:error]
|
41
|
+
last_input.opts[:error_attr] = input.opts[:error_attr] if input.opts[:error_attr]
|
42
|
+
last_input.opts[:error_handler] = :default
|
43
|
+
|
44
|
+
tag
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ErrorHandler::AfterLegend < ErrorHandler
|
49
|
+
Forme.register_transformer(:error_handler, :after_legend, new)
|
50
|
+
|
51
|
+
def call(tag, input)
|
52
|
+
return super unless tag.is_a?(Array)
|
53
|
+
return super unless tag.first.is_a?(Tag)
|
54
|
+
return super unless tag.first.type == :legend
|
55
|
+
|
56
|
+
first_input = input.opts[:first_input]
|
57
|
+
attr = first_input.opts[:attr] ||= {}
|
58
|
+
Forme.attr_classes(attr, 'error')
|
59
|
+
attr['aria-invalid'] = 'true'
|
60
|
+
attr['aria-describedby'] = input.opts[:error_id] = "#{first_input.opts[:id]}_error_message"
|
61
|
+
|
62
|
+
tag.insert(1, error_tag(input))
|
18
63
|
end
|
19
64
|
end
|
20
65
|
end
|
@@ -61,7 +61,6 @@ module Forme
|
|
61
61
|
@attr = attr ? attr.dup : {}
|
62
62
|
@opts = input.opts
|
63
63
|
normalize_options
|
64
|
-
|
65
64
|
tag = if html = input.opts[:html]
|
66
65
|
html = html.call(input) if html.respond_to?(:call)
|
67
66
|
form.raw(html)
|
@@ -158,9 +157,10 @@ module Forme
|
|
158
157
|
ops = ops.merge(@opts[:select_options]) if @opts[:select_options]
|
159
158
|
first_input = true
|
160
159
|
format = DATE_SELECT_FORMAT
|
160
|
+
@opts[:select_labels] ||= {}
|
161
161
|
order.map do |x|
|
162
162
|
next x if x.is_a?(String)
|
163
|
-
opts = @opts.merge(:label
|
163
|
+
opts = @opts.merge(:label=>@opts[:select_labels][x], :wrapper=>nil, :error=>nil, :name=>"#{name}[#{x}]", :value=>values[x], :options=>ops[x].map{|y| [sprintf(format, y), y]})
|
164
164
|
opts[:id] = if first_input
|
165
165
|
first_input = false
|
166
166
|
id
|
@@ -221,23 +221,22 @@ module Forme
|
|
221
221
|
key = @opts[:key]
|
222
222
|
name = @opts[:name]
|
223
223
|
id = @opts[:id]
|
224
|
-
|
225
|
-
|
226
|
-
end
|
227
|
-
if @opts[:label]
|
228
|
-
@opts[:set_label] = @opts.delete(:label)
|
229
|
-
end
|
224
|
+
@opts[:labeler] ||= :span
|
225
|
+
@opts[:error_handler] ||= :set
|
230
226
|
|
231
227
|
tag_wrapper = Forme.transformer(:tag_wrapper, @opts.delete(:tag_wrapper), @input.form_opts) || :default
|
232
228
|
tag_labeler = Forme.transformer(:labeler, @opts.delete(:tag_labeler), @input.form_opts) || :default
|
233
229
|
wrapper = @opts.fetch(:wrapper){@opts[:wrapper] = @input.form_opts[:set_wrapper] || @input.form_opts[:wrapper]}
|
234
230
|
wrapper = Forme.transformer(:wrapper, wrapper)
|
231
|
+
tag_label_attr = @opts[:tag_label_attr] || @opts[:label_attr]
|
235
232
|
|
236
|
-
|
233
|
+
first_input = nil
|
234
|
+
last_input = nil
|
235
|
+
ret = process_select_optgroups(:_format_set_optgroup) do |label, value, sel, attrs|
|
237
236
|
value = label if value.nil?
|
238
237
|
label_attr = {:class=>:option}
|
239
|
-
label_attr.merge!(
|
240
|
-
r_opts = attrs.merge(tag_attrs).merge(:label=>label||value, :label_attr=>label_attr, :wrapper=>tag_wrapper, :labeler=>tag_labeler)
|
238
|
+
label_attr.merge!(tag_label_attr) if tag_label_attr
|
239
|
+
r_opts = attrs.merge(tag_attrs).merge(:label=>label||value, :label_attr=>label_attr, :wrapper=>tag_wrapper, :labeler=>tag_labeler, :error=>nil, :error_attr=>nil)
|
241
240
|
if r_opts[:value].nil?
|
242
241
|
r_opts[:value] = value unless value.nil?
|
243
242
|
end
|
@@ -255,31 +254,15 @@ module Forme
|
|
255
254
|
r_opts[:key_id] ||= value
|
256
255
|
end
|
257
256
|
|
258
|
-
form._input(type, r_opts)
|
259
|
-
|
260
|
-
|
261
|
-
if @opts[:set_error]
|
262
|
-
_add_set_error(tags)
|
257
|
+
input = form._input(type, r_opts)
|
258
|
+
first_input ||= input
|
259
|
+
last_input = input
|
263
260
|
end
|
264
261
|
|
265
|
-
|
266
|
-
|
267
|
-
tags
|
268
|
-
end
|
262
|
+
@opts[:first_input] = first_input
|
263
|
+
@opts[:last_input] = last_input
|
269
264
|
|
270
|
-
|
271
|
-
form._tag(:span, {:class=>:label}, @opts[:set_label])
|
272
|
-
end
|
273
|
-
|
274
|
-
def _add_set_error(tags)
|
275
|
-
if (last_input = tags.last) && last_input.is_a?(Input)
|
276
|
-
last_input.opts[:error] = @opts[:set_error]
|
277
|
-
last_input.opts[:error_attr] = @opts[:error_attr] if @opts[:error_attr]
|
278
|
-
else
|
279
|
-
attr = @opts[:error_attr] || {}
|
280
|
-
Forme.attr_classes(attr, 'error_message')
|
281
|
-
tags << form._tag(:span, attr, [@opts[:set_error]])
|
282
|
-
end
|
265
|
+
ret
|
283
266
|
end
|
284
267
|
|
285
268
|
# Formats a textarea. Respects the following options:
|
@@ -321,7 +304,19 @@ module Forme
|
|
321
304
|
handle_errors_option
|
322
305
|
|
323
306
|
Forme.attr_classes(@attr, @opts[:class]) if @opts.has_key?(:class)
|
324
|
-
|
307
|
+
|
308
|
+
if @opts[:error]
|
309
|
+
Forme.attr_classes(@attr, 'error')
|
310
|
+
@attr["aria-invalid"] = "true"
|
311
|
+
if @opts.fetch(:error_handler, true)
|
312
|
+
unless @opts[:error_id]
|
313
|
+
if id = @attr[:id] || @attr['id']
|
314
|
+
error_id = @attr['aria-describedby'] ||= "#{id}_error_message"
|
315
|
+
@opts[:error_id] = error_id
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
325
320
|
|
326
321
|
if data = opts[:data]
|
327
322
|
data.each do |k, v|
|
@@ -540,8 +535,11 @@ module Forme
|
|
540
535
|
end
|
541
536
|
|
542
537
|
# Use a span with text instead of an input field.
|
538
|
+
# For hidden inputs, do not show anything
|
543
539
|
def _format_input(type)
|
544
|
-
|
540
|
+
unless type.to_s == 'hidden'
|
541
|
+
tag(:span, {'class'=>'readonly-text'}, @attr[:value])
|
542
|
+
end
|
545
543
|
end
|
546
544
|
|
547
545
|
# Disabled radio button inputs.
|
@@ -10,7 +10,7 @@ module Forme
|
|
10
10
|
# Wrap the inputs in a <fieldset>. If the :legend
|
11
11
|
# option is given, add a <legend> tag as the first
|
12
12
|
# child of the fieldset.
|
13
|
-
def call(form, opts)
|
13
|
+
def call(form, opts, &block)
|
14
14
|
attr = opts[:attr] ? opts[:attr].dup : {}
|
15
15
|
Forme.attr_classes(attr, 'inputs')
|
16
16
|
if legend = opts[:legend]
|
@@ -19,7 +19,7 @@ module Forme
|
|
19
19
|
yield
|
20
20
|
end
|
21
21
|
else
|
22
|
-
form.tag(:fieldset, attr, &
|
22
|
+
form.tag(:fieldset, attr, &block)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -77,4 +77,23 @@ module Forme
|
|
77
77
|
t
|
78
78
|
end
|
79
79
|
end
|
80
|
+
|
81
|
+
class Labeler::Span
|
82
|
+
Forme.register_transformer(:labeler, :span, new)
|
83
|
+
|
84
|
+
def call(tag, input)
|
85
|
+
label_attr = input.opts[:label_attr]
|
86
|
+
label_attr = label_attr ? label_attr.dup : {}
|
87
|
+
Forme.attr_classes(label_attr, "label")
|
88
|
+
[input.tag(:span, label_attr, input.opts[:label]), tag]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Labeler::Legend
|
93
|
+
Forme.register_transformer(:labeler, :legend, new)
|
94
|
+
|
95
|
+
def call(tag, input)
|
96
|
+
[input.tag(:legend, input.opts[:label_attr], input.opts[:label]), tag]
|
97
|
+
end
|
98
|
+
end
|
80
99
|
end
|
data/lib/forme/version.rb
CHANGED
data/spec/forme_spec.rb
CHANGED
@@ -116,13 +116,13 @@ describe "Forme plain forms" do
|
|
116
116
|
|
117
117
|
it "should consider form's :errors hash based on the :key option" do
|
118
118
|
@f.opts[:errors] = { 'foo' => 'must be present' }
|
119
|
-
@f.input(:text, :key=>"foo").to_s.must_equal "<input class=\"error\" id=\"foo\" name=\"foo\" type=\"text\"/><span class=\"error_message\">must be present</span>"
|
119
|
+
@f.input(:text, :key=>"foo").to_s.must_equal "<input aria-describedby=\"foo_error_message\" aria-invalid=\"true\" class=\"error\" id=\"foo\" name=\"foo\" type=\"text\"/><span class=\"error_message\" id=\"foo_error_message\">must be present</span>"
|
120
120
|
end
|
121
121
|
|
122
122
|
it "should consider form's :errors hash based on the :key option when using namespaces" do
|
123
123
|
@f.opts[:errors] = { 'bar' => { 'foo' => 'must be present' } }
|
124
124
|
@f.with_opts(:namespace=>['bar']) do
|
125
|
-
@f.input(:text, :key=>"foo").to_s.must_equal "<input class=\"error\" id=\"bar_foo\" name=\"bar[foo]\" type=\"text\"/><span class=\"error_message\">must be present</span>"
|
125
|
+
@f.input(:text, :key=>"foo").to_s.must_equal "<input aria-describedby=\"bar_foo_error_message\" aria-invalid=\"true\" class=\"error\" id=\"bar_foo\" name=\"bar[foo]\" type=\"text\"/><span class=\"error_message\" id=\"bar_foo_error_message\">must be present</span>"
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
@@ -301,6 +301,10 @@ describe "Forme plain forms" do
|
|
301
301
|
@f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5)).to_s.must_equal %{<select id="bar" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>}
|
302
302
|
end
|
303
303
|
|
304
|
+
it "should use labels for select boxes for dates if the :as=>:select and :select_labels options are given" do
|
305
|
+
@f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :select_labels=>{:year=>'Y', :month=>'M', :day=>'D'}, :labeler=>:explicit).to_s.must_equal %{<label class="label-before" for="bar">Y</label><select id="bar" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<label class="label-before" for="bar_month">M</label><select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<label class="label-before" for="bar_day">D</label><select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>}
|
306
|
+
end
|
307
|
+
|
304
308
|
it "should allow ordering date select boxes via :order" do
|
305
309
|
@f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :order=>[:month, '/', :day, '/', :year]).to_s.must_equal %{<select id="bar" name="foo[month]">#{sel(1..12, 6)}</select>/<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>/<select id="bar_year" name="foo[year]">#{sel(1900..2050, 2011)}</select>}
|
306
310
|
end
|
@@ -433,7 +437,11 @@ describe "Forme plain forms" do
|
|
433
437
|
end
|
434
438
|
|
435
439
|
it "should create set of radio buttons with :error and :error_attr options" do
|
436
|
-
@f.input(:radioset, :options=>[1, 2, 3], :selected=>2, :error=>'foo', :error_attr=>{'bar'=>'baz'}).to_s.must_equal '<label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input class="error" type="radio" value="3"/> 3</label><span bar="baz" class="error_message">foo</span>'
|
440
|
+
@f.input(:radioset, :options=>[1, 2, 3], :selected=>2, :error=>'foo', :error_attr=>{'bar'=>'baz'}).to_s.must_equal '<label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input aria-invalid="true" class="error" type="radio" value="3"/> 3</label><span bar="baz" class="error_message">foo</span>'
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should support custom error_handler for set of radio buttons" do
|
444
|
+
@f.input(:radioset, :options=>[1, 2, 3], :selected=>2, :error=>'foo', :error_attr=>{'bar'=>'baz'}, :error_handler=>lambda{|tag, input| input.tag(:div, {}, tag)}).to_s.must_equal '<div><label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input type="radio" value="3"/> 3</label></div>'
|
437
445
|
end
|
438
446
|
|
439
447
|
it "should create set of checkbox buttons" do
|
@@ -457,10 +465,26 @@ describe "Forme plain forms" do
|
|
457
465
|
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :label=>'foo').to_s.must_equal '<span class="label">foo</span><label class="option"><input type="checkbox" value="1"/> a</label><label class="option"><input type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label>'
|
458
466
|
end
|
459
467
|
|
468
|
+
it "should support fieldset/legend for checkboxsets" do
|
469
|
+
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :label=>'foo', :labeler=>:legend, :wrapper=>:fieldset).to_s.must_equal '<fieldset><legend>foo</legend><label class="option"><input type="checkbox" value="1"/> a</label><label class="option"><input type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label></fieldset>'
|
470
|
+
end
|
471
|
+
|
472
|
+
it "should support legend with attributes for checkboxsets" do
|
473
|
+
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :label=>'foo', :label_attr=>{:class=>"baz"}, :tag_label_attr=>{:class=>"bar"}, :labeler=>:legend, :wrapper=>:fieldset).to_s.must_equal '<fieldset><legend class="baz">foo</legend><label class="bar"><input type="checkbox" value="1"/> a</label><label class="bar"><input type="checkbox" value="2"/> b</label><label class="bar"><input type="checkbox" value="3"/> c</label></fieldset>'
|
474
|
+
end
|
475
|
+
|
476
|
+
it "should support legend with attributes for checkboxsets, handling errors with :error_handler=>:after_legend" do
|
477
|
+
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :id=>:quux, :label=>'foo', :label_attr=>{:class=>"baz"}, :tag_label_attr=>{:class=>"bar"}, :labeler=>:legend, :wrapper=>:fieldset, :error=>'bar2', :error_handler=>:after_legend).to_s.must_equal '<fieldset><legend class="baz">foo</legend><span class="error_message" id="quux_1_error_message">bar2</span><label class="bar"><input aria-describedby="quux_1_error_message" aria-invalid="true" class="error" id="quux_1" type="checkbox" value="1"/> a</label><label class="bar"><input id="quux_2" type="checkbox" value="2"/> b</label><label class="bar"><input id="quux_3" type="checkbox" value="3"/> c</label></fieldset>'
|
478
|
+
end
|
479
|
+
|
460
480
|
it "should support :tag_labeler for checkboxsets" do
|
461
481
|
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :tag_labeler=>:explicit).to_s.must_equal '<input type="checkbox" value="1"/><label class="option label-after">a</label><input type="checkbox" value="2"/><label class="option label-after">b</label><input type="checkbox" value="3"/><label class="option label-after">c</label>'
|
462
482
|
end
|
463
483
|
|
484
|
+
it "should support custom :labeler for checkboxsets" do
|
485
|
+
@f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :label=>'foo', :labeler=>lambda{|tag, input| input.tag(:div, {}, tag)}).to_s.must_equal '<div><label class="option"><input type="checkbox" value="1"/> a</label><label class="option"><input type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label></div>'
|
486
|
+
end
|
487
|
+
|
464
488
|
it "should create set of checkbox buttons with options and values with hashes" do
|
465
489
|
@f.input(:checkboxset, :options=>[[:a, {:attr=>{:foo=>1}}], [:b, {:class=>'foo', :value=>2}], [:c, {:id=>:baz}]], :selected=>2).to_s.must_equal '<label class="option"><input foo="1" type="checkbox" value="a"/> a</label><label class="option"><input checked="checked" class="foo" type="checkbox" value="2"/> b</label><label class="option"><input id="baz" type="checkbox" value="c"/> c</label>'
|
466
490
|
end
|
@@ -491,7 +515,7 @@ describe "Forme plain forms" do
|
|
491
515
|
end
|
492
516
|
|
493
517
|
it "should respect the :error option for checkbox sets" do
|
494
|
-
@f.input(:checkboxset, :options=>[1, 2, 3], :error=>'foo', :value=>2).to_s.must_equal '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input class="error" type="checkbox" value="3"/> 3</label><span class="error_message">foo</span>'
|
518
|
+
@f.input(:checkboxset, :options=>[1, 2, 3], :error=>'foo', :value=>2).to_s.must_equal '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input aria-invalid="true" class="error" type="checkbox" value="3"/> 3</label><span class="error_message">foo</span>'
|
495
519
|
end
|
496
520
|
|
497
521
|
it "should create set of checkbox buttons with fieldsets and legends for optgroups" do
|
@@ -558,19 +582,23 @@ describe "Forme plain forms" do
|
|
558
582
|
end
|
559
583
|
|
560
584
|
it "should automatically note the input has errors if :error option is used" do
|
561
|
-
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.must_equal '<input class="error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
585
|
+
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.must_equal '<input aria-invalid="true" class="error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
562
586
|
end
|
563
587
|
|
564
588
|
it "should add an error message after the label" do
|
565
|
-
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :label=>"Foo").to_s.must_equal '<label>Foo: <input class="error" type="text" value="foo"/></label><span class="error_message">Bad Stuff!</span>'
|
589
|
+
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :label=>"Foo").to_s.must_equal '<label>Foo: <input aria-invalid="true" class="error" type="text" value="foo"/></label><span class="error_message">Bad Stuff!</span>'
|
566
590
|
end
|
567
591
|
|
568
592
|
it "should add to existing :class option if :error option is used" do
|
569
|
-
@f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.must_equal '<input class="bar error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
593
|
+
@f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.must_equal '<input aria-invalid="true" class="bar error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
570
594
|
end
|
571
595
|
|
572
596
|
it "should respect :error_attr option for setting the attributes for the error message span" do
|
573
|
-
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :error_attr=>{:class=>'foo'}).to_s.must_equal '<input class="error" type="text" value="foo"/><span class="foo error_message">Bad Stuff!</span>'
|
597
|
+
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo', :error_attr=>{:class=>'foo'}).to_s.must_equal '<input aria-invalid="true" class="error" type="text" value="foo"/><span class="foo error_message">Bad Stuff!</span>'
|
598
|
+
end
|
599
|
+
|
600
|
+
it "should use aria-describedby and aria-invalid tags for errors with where the id attribute can be determined" do
|
601
|
+
@f.input(:text, :error=>'Bad Stuff!', :id=>:bar, :value=>'foo', :error_attr=>{:class=>'foo'}).to_s.must_equal '<input aria-describedby="bar_error_message" aria-invalid="true" class="error" id="bar" type="text" value="foo"/><span class="foo error_message" id="bar_error_message">Bad Stuff!</span>'
|
574
602
|
end
|
575
603
|
|
576
604
|
it "#open should return an opening tag" do
|
@@ -696,7 +724,7 @@ describe "Forme plain forms" do
|
|
696
724
|
end
|
697
725
|
|
698
726
|
it "inputs should have helper displayed inside wrapper, after error" do
|
699
|
-
@f.input(:text, :help=>"List type of foo", :error=>'bad', :wrapper=>:li).to_s.must_equal '<li><input class="error" type="text"/><span class="error_message">bad</span><span class="helper">List type of foo</span></li>'
|
727
|
+
@f.input(:text, :help=>"List type of foo", :error=>'bad', :wrapper=>:li).to_s.must_equal '<li><input aria-invalid="true" class="error" type="text"/><span class="error_message">bad</span><span class="helper">List type of foo</span></li>'
|
700
728
|
end
|
701
729
|
|
702
730
|
it "inputs should accept a :formatter option to use a custom formatter" do
|
@@ -729,7 +757,7 @@ describe "Forme plain forms" do
|
|
729
757
|
end
|
730
758
|
|
731
759
|
it "inputs should accept a :error_handler option to use a custom error_handler" do
|
732
|
-
@f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.must_equal '<textarea class="error" id="foo"></textarea>!!! bar'
|
760
|
+
@f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.must_equal '<textarea aria-describedby="foo_error_message" aria-invalid="true" class="error" id="foo"></textarea>!!! bar'
|
733
761
|
end
|
734
762
|
|
735
763
|
it "#inputs should accept a :inputs_wrapper option to use a custom inputs_wrapper" do
|
@@ -745,7 +773,7 @@ describe "Forme plain forms" do
|
|
745
773
|
end
|
746
774
|
|
747
775
|
it "inputs should accept a :error_handler=>nil option to not use an error_handler" do
|
748
|
-
@f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.must_equal '<textarea class="error" id="foo"></textarea>'
|
776
|
+
@f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.must_equal '<textarea aria-invalid="true" class="error" id="foo"></textarea>'
|
749
777
|
end
|
750
778
|
|
751
779
|
it "#inputs should accept a :inputs_wrapper=>nil option to not use an inputs_wrapper" do
|
@@ -819,7 +847,7 @@ describe "Forme custom" do
|
|
819
847
|
end
|
820
848
|
|
821
849
|
it "error_handlers can be specified as a proc" do
|
822
|
-
Forme::Form.new(:error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}).input(:textarea, :name=>'foo', :error=>'bar').to_s.must_equal '<textarea class="error" name="foo"></textarea>!!! bar'
|
850
|
+
Forme::Form.new(:error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}).input(:textarea, :name=>'foo', :error=>'bar').to_s.must_equal '<textarea aria-invalid="true" class="error" name="foo"></textarea>!!! bar'
|
823
851
|
end
|
824
852
|
|
825
853
|
it "wrappers can be specified as a proc" do
|
@@ -854,6 +882,10 @@ describe "Forme built-in custom" do
|
|
854
882
|
Forme::Form.new(:formatter=>:readonly).input(:select, :label=>"Foo", :options=>[1, 2, 3], :value=>2).to_s.must_equal "<label>Foo: <span>2</span></label>"
|
855
883
|
end
|
856
884
|
|
885
|
+
it "formatter: readonly removes hidden inputs" do
|
886
|
+
Forme::Form.new(:formatter=>:readonly).input(:hidden, :value=>"Bar").to_s.must_equal ""
|
887
|
+
end
|
888
|
+
|
857
889
|
it "formatter: readonly formats text into paragraphs for textarea inputs" do
|
858
890
|
Forme::Form.new(:formatter=>:readonly).input(:textarea, :label=>"Foo", :value=>"\n Bar\nBaz\n\nQuuz\n\n1\n2 \n").to_s.must_equal "<label>Foo: <div class=\"readonly-textarea\"><p> Bar<br />Baz</p><p>Quuz</p><p>1<br />2 </p></div></label>"
|
859
891
|
end
|
@@ -877,7 +909,7 @@ describe "Forme built-in custom" do
|
|
877
909
|
end
|
878
910
|
|
879
911
|
it "labeler: explicit should handle tags with errors" do
|
880
|
-
Forme::Form.new(:labeler=>:explicit).input(:text, :error=>'Bad Stuff!', :value=>'f', :id=>'foo', :label=>'bar').to_s.must_equal '<label class="label-before" for="foo">bar</label><input class="error" id="foo" type="text" value="f"/><span class="error_message">Bad Stuff!</span>'
|
912
|
+
Forme::Form.new(:labeler=>:explicit).input(:text, :error=>'Bad Stuff!', :value=>'f', :id=>'foo', :label=>'bar').to_s.must_equal '<label class="label-before" for="foo">bar</label><input aria-describedby="foo_error_message" aria-invalid="true" class="error" id="foo" type="text" value="f"/><span class="error_message" id="foo_error_message">Bad Stuff!</span>'
|
881
913
|
end
|
882
914
|
|
883
915
|
it "wrapper: li wraps tag in an li" do
|
@@ -915,7 +947,7 @@ describe "Forme built-in custom" do
|
|
915
947
|
end
|
916
948
|
|
917
949
|
it "wrapper: trtd should use at most 2 td tags" do
|
918
|
-
Forme::Form.new(:wrapper=>:trtd, :labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'Foo', :error=>'Bar').to_s.must_equal '<tr><td><label class="label-before" for="foo">Foo</label></td><td><textarea class="error" id="foo"></textarea><span class="error_message">Bar</span></td></tr>'
|
950
|
+
Forme::Form.new(:wrapper=>:trtd, :labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'Foo', :error=>'Bar').to_s.must_equal '<tr><td><label class="label-before" for="foo">Foo</label></td><td><textarea aria-describedby="foo_error_message" aria-invalid="true" class="error" id="foo"></textarea><span class="error_message" id="foo_error_message">Bar</span></td></tr>'
|
919
951
|
end
|
920
952
|
|
921
953
|
it "wrapper: trtd should handle inputs with label after" do
|
@@ -20,7 +20,15 @@ rescue LoadError
|
|
20
20
|
end
|
21
21
|
|
22
22
|
class FormeRodaTest < Roda
|
23
|
-
|
23
|
+
opts[:check_dynamic_arity] = opts[:check_arity] = :warn
|
24
|
+
|
25
|
+
if defined?(Roda::RodaVersionNumber) && Roda::RodaVersionNumber >= 30100
|
26
|
+
require 'roda/session_middleware'
|
27
|
+
opts[:sessions_convert_symbols] = true
|
28
|
+
use RodaSessionMiddleware, :secret=>SecureRandom.random_bytes(64), :key=>'rack.session'
|
29
|
+
else
|
30
|
+
use Rack::Session::Cookie, :secret => "__a_very_long_string__"
|
31
|
+
end
|
24
32
|
|
25
33
|
def erb(s, opts={})
|
26
34
|
render(opts.merge(:inline=>s))
|
data/spec/sequel_plugin_spec.rb
CHANGED
@@ -134,7 +134,7 @@ describe "Forme Sequel::Model forms" do
|
|
134
134
|
|
135
135
|
it "should handle errors on radio buttons for boolean fields if :as=>:radio is used" do
|
136
136
|
@ab.errors.add(:platinum, 'foo')
|
137
|
-
@b.input(:platinum, :as=>:radio).to_s.must_equal '<span class="label">Platinum</span><label class="option"><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label class="option"><input checked="checked" class="error" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label><span class="error_message">foo</span>'
|
137
|
+
@b.input(:platinum, :as=>:radio).to_s.must_equal '<span class="label">Platinum</span><label class="option"><input id="album_platinum_yes" name="album[platinum]" type="radio" value="t"/> Yes</label><label class="option"><input aria-describedby="album_platinum_no_error_message" aria-invalid="true" checked="checked" class="error" id="album_platinum_no" name="album[platinum]" type="radio" value="f"/> No</label><span class="error_message" id="album_platinum_no_error_message">foo</span>'
|
138
138
|
end
|
139
139
|
|
140
140
|
it "should handle Raw :label options if :as=>:radio is used" do
|
@@ -272,8 +272,8 @@ describe "Forme Sequel::Model forms" do
|
|
272
272
|
|
273
273
|
it "should handle an error message on the underlying column for pg_array_to_many associations" do
|
274
274
|
@ab.errors.add(:atag_ids, 'tis not valid')
|
275
|
-
@b.input(:atags).to_s.must_equal '<label>Atags: <select class="error" id="album_atag_ids" multiple="multiple" name="album[atag_ids][]"><option selected="selected" value="1">s</option><option selected="selected" value="2">t</option><option value="3">u</option></select></label><span class="error_message">tis not valid</span>'
|
276
|
-
@b.input(:atags, :as=>:checkbox).to_s.must_equal '<span class="label">Atags</span><label class="option"><input checked="checked" id="album_atag_ids_1" name="album[atag_ids][]" type="checkbox" value="1"/> s</label><label class="option"><input checked="checked" id="album_atag_ids_2" name="album[atag_ids][]" type="checkbox" value="2"/> t</label><label class="option"><input class="error" id="album_atag_ids_3" name="album[atag_ids][]" type="checkbox" value="3"/> u</label><span class="error_message">tis not valid</span>'
|
275
|
+
@b.input(:atags).to_s.must_equal '<label>Atags: <select aria-describedby="album_atag_ids_error_message" aria-invalid="true" class="error" id="album_atag_ids" multiple="multiple" name="album[atag_ids][]"><option selected="selected" value="1">s</option><option selected="selected" value="2">t</option><option value="3">u</option></select></label><span class="error_message" id="album_atag_ids_error_message">tis not valid</span>'
|
276
|
+
@b.input(:atags, :as=>:checkbox).to_s.must_equal '<span class="label">Atags</span><label class="option"><input checked="checked" id="album_atag_ids_1" name="album[atag_ids][]" type="checkbox" value="1"/> s</label><label class="option"><input checked="checked" id="album_atag_ids_2" name="album[atag_ids][]" type="checkbox" value="2"/> t</label><label class="option"><input aria-describedby="album_atag_ids_3_error_message" aria-invalid="true" class="error" id="album_atag_ids_3" name="album[atag_ids][]" type="checkbox" value="3"/> u</label><span class="error_message" id="album_atag_ids_3_error_message">tis not valid</span>'
|
277
277
|
end
|
278
278
|
|
279
279
|
it "should use a regular select box for *_to_many associations if multiple if false" do
|
@@ -318,7 +318,7 @@ describe "Forme Sequel::Model forms" do
|
|
318
318
|
|
319
319
|
it "should handle errors on methods not backed by columns" do
|
320
320
|
@ab.errors.add(:artist_name, 'foo')
|
321
|
-
@b.input(:artist_name).to_s.must_equal '<label>Artist name: <input class="error" id="album_artist_name" name="album[artist_name]" type="text" value="a"/></label><span class="error_message">foo</span>'
|
321
|
+
@b.input(:artist_name).to_s.must_equal '<label>Artist name: <input aria-describedby="album_artist_name_error_message" aria-invalid="true" class="error" id="album_artist_name" name="album[artist_name]" type="text" value="a"/></label><span class="error_message" id="album_artist_name_error_message">foo</span>'
|
322
322
|
end
|
323
323
|
|
324
324
|
it "should respect a :type option with a schema type as the input type for methods not backed by columns" do
|
@@ -333,12 +333,12 @@ describe "Forme Sequel::Model forms" do
|
|
333
333
|
|
334
334
|
it "should correctly show an error message if there is one" do
|
335
335
|
@ab.errors.add(:name, 'tis not valid')
|
336
|
-
@b.input(:name).to_s.must_equal '<label>Name: <input class="error" id="album_name" maxlength="255" name="album[name]" type="text" value="b"/></label><span class="error_message">tis not valid</span>'
|
336
|
+
@b.input(:name).to_s.must_equal '<label>Name: <input aria-describedby="album_name_error_message" aria-invalid="true" class="error" id="album_name" maxlength="255" name="album[name]" type="text" value="b"/></label><span class="error_message" id="album_name_error_message">tis not valid</span>'
|
337
337
|
end
|
338
338
|
|
339
339
|
it "should correctly show an error message for many_to_one associations if there is one" do
|
340
340
|
@ab.errors.add(:artist_id, 'tis not valid')
|
341
|
-
@b.input(:artist).to_s.must_equal '<label>Artist: <select class="error" id="album_artist_id" name="album[artist_id]"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label><span class="error_message">tis not valid</span>'
|
341
|
+
@b.input(:artist).to_s.must_equal '<label>Artist: <select aria-describedby="album_artist_id_error_message" aria-invalid="true" class="error" id="album_artist_id" name="album[artist_id]"><option value=""></option><option selected="selected" value="1">a</option><option value="2">d</option></select></label><span class="error_message" id="album_artist_id_error_message">tis not valid</span>'
|
342
342
|
end
|
343
343
|
|
344
344
|
it "should raise an error for unhandled associations" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -220,8 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
220
|
- !ruby/object:Gem::Version
|
221
221
|
version: '0'
|
222
222
|
requirements: []
|
223
|
-
|
224
|
-
rubygems_version: 2.7.6
|
223
|
+
rubygems_version: 3.0.3
|
225
224
|
signing_key:
|
226
225
|
specification_version: 4
|
227
226
|
summary: HTML forms library
|