forme 1.9.0 → 1.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
  SHA256:
3
- metadata.gz: abf3346d90f5f4eddb69a0c0c2a63a2fcee549cf2b928bec7ab8a9505a8135aa
4
- data.tar.gz: 577dccded6b59dae158e5275b7bed4dcb87a9756b29d2e3f367accca1f32313b
3
+ metadata.gz: 581902a62cc974ce05fecf52a4b7debd41b5d89f5ba151c1c03a2f0589f15e7e
4
+ data.tar.gz: 5252e5dca95690ddf46341e443954058644f41c67e2109d7692a6dfb8c3b3ee8
5
5
  SHA512:
6
- metadata.gz: 35dbc13c7de3c746a229b0f4d6026a0dfc3b8fa9dda3952ae3aa2117c6b1ad843ec07c3c40ab754cd2ae91c3ffea83cb281ee48539b886b48b832f2f1f887bab
7
- data.tar.gz: 39fdd8a5b87777f1fd1831adf05c100624619e7e1cdf09d9e207d8118a8ab154971f6d229d7db1c3141faf423816a68a66b67001fd4e0b29462af2a545493e09
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)
@@ -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
- Both of these respect the following options:
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
@@ -214,7 +214,7 @@ module Forme
214
214
  yield
215
215
  end
216
216
  else
217
- form.tag(:fieldset, attr, &Proc.new)
217
+ form.tag(:fieldset, attr, &block)
218
218
  end
219
219
  end
220
220
  end
@@ -59,7 +59,7 @@ module Forme
59
59
  ins = opts[:inputs]
60
60
  button = opts[:button]
61
61
  if ins || button
62
- block = Proc.new do |form|
62
+ block = proc do |form|
63
63
  form._inputs(ins, opts) if ins
64
64
  yield form if block_given?
65
65
  form.emit(form.button(button)) if button
@@ -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
- [tag, input.tag(:span, attr, input.opts[:error])]
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=>nil, :wrapper=>nil, :error=>nil, :name=>"#{name}[#{x}]", :value=>values[x], :options=>ops[x].map{|y| [sprintf(format, y), y]})
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
- if @opts[:error]
225
- @opts[:set_error] = @opts.delete(:error)
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
- tags = process_select_optgroups(:_format_set_optgroup) do |label, value, sel, attrs|
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!(@opts[:label_attr]) if @opts[:label_attr]
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
- end
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
- tags.unshift(set_label) if @opts[:set_label]
266
-
267
- tags
268
- end
262
+ @opts[:first_input] = first_input
263
+ @opts[:last_input] = last_input
269
264
 
270
- def set_label
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
- Forme.attr_classes(@attr, 'error') if @opts[:error]
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
- tag(:span, {'class'=>'readonly-text'}, @attr[:value])
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, &Proc.new)
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
@@ -23,7 +23,7 @@ module Forme
23
23
  input.tag(@type, input.opts[:wrapper_attr], super)
24
24
  end
25
25
 
26
- [:li, :p, :div, :span, :td].each do |x|
26
+ [:li, :p, :div, :span, :td, :fieldset].each do |x|
27
27
  Forme.register_transformer(:wrapper, x, new(x))
28
28
  end
29
29
  end
@@ -6,7 +6,7 @@ module Forme
6
6
  MAJOR = 1
7
7
 
8
8
  # The minor version of Forme, updated for new feature releases of Forme.
9
- MINOR = 9
9
+ MINOR = 10
10
10
 
11
11
  # The patch version of Forme, updated only for bug fixes from the last
12
12
  # feature release.
@@ -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
- use Rack::Session::Cookie, :secret => "__a_very_long_string__"
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))
@@ -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.9.0
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: 2018-11-16 00:00:00.000000000 Z
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
- rubyforge_project:
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