forme 2.1.0 → 2.3.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: 16429cabb255a24eacd8d108a6c0d1ed771581148f5f344a876ceb1da4082a3f
4
- data.tar.gz: 7fc3607cba35093e78bdfb3f6892bd94289c698b6d015e1a701303e5f5435b1a
3
+ metadata.gz: 13efa41ba160d80619b779cda0ad94581b37695e9fb8caedc696d26c91c92d87
4
+ data.tar.gz: 6558cf408b4573b3822c566c8e48b856de47009c6293831e0cdcc3fed7f4ebc2
5
5
  SHA512:
6
- metadata.gz: e399a4c2aa701ee112c1c3ed4f95854611781929b5ebcdc7b0c925c703d80b79d5cb77c1b1427e60be98b47e6308aac3cb2a231895874696a8265502fced126a
7
- data.tar.gz: 4397400180f4398ca5a553acf2b2845607952cfadfa8126ea88e473b161b8ac7e04589fcf89a62291b3e6218dbb6cf29d83825090c076d020181d3d1f2b05de7
6
+ metadata.gz: 42d8dd057d905a8cb44610c9b3c20c9d055d0f0495b8ec94b020a637d0b10f5c1919ebc697e0b4f8970a29fcb511661cc56d622dc1d91eb8f347ab62fe36d7c4
7
+ data.tar.gz: 10beb8c2109850be4c1fb5d0c46d13218269c8b65f604cda930024eab8ff3838f32ab70256696d93f5c17f3e011d5dad0450511051a6abda40e75e37c1bbf2eb
data/CHANGELOG CHANGED
@@ -1,3 +1,19 @@
1
+ === 2.3.0 (2022-11-15)
2
+
3
+ * Add forme/bs5 for Bootstrap 5 support (janko) (#106)
4
+
5
+ * Raise exception if attempting to load Roda forme_set plugin without setting :secret option (janko) (#104)
6
+
7
+ === 2.2.0 (2022-06-28)
8
+
9
+ * Use inputmode and pattern attributes instead of type=number for integer fields in the Sequel forme plugin (jeremyevans)
10
+
11
+ * Respect explicit nil/false :value option for boolean inputs in the Sequel forme plugin (jeremyevans)
12
+
13
+ * In bs3 support, make sure error spans have id referenced by aria-describedby (jeremyevans)
14
+
15
+ * Set aria-describedby attribute automatically even if :error_id is given manually (jeremyevans)
16
+
1
17
  === 2.1.0 (2022-05-25)
2
18
 
3
19
  * Avoid hidden inputs inside tbody tags in subform in the Sequel::Model support, since that results in invalid HTML (jeremyevans)
data/README.rdoc CHANGED
@@ -49,7 +49,7 @@ This results in the following HTML:
49
49
  <input id="album_name" name="album[name]" type="text" value="Rising Force"/>
50
50
  </label>
51
51
  <label>Copies Sold:
52
- <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/>
52
+ <input id="album_copies_sold" inputmode="numeric" name="album[copies_sold]" pattern="-?[0-9]*" type="text" value="100000"/>
53
53
  </label>
54
54
  </form>
55
55
 
@@ -443,12 +443,12 @@ form similar to:
443
443
 
444
444
  <input id="album_tracks_attributes_0_id" name="album[tracks_attributes][0][id]" type="hidden" value="1"/>
445
445
  <fieldset class="inputs"><legend>Track #1</legend>
446
- <label>Number: <input id="album_tracks_attributes_0_number" name="album[tracks_attributes][0][number]" type="number" value="1"/></label>
446
+ <label>Number: <input id="album_tracks_attributes_0_number" inputmode="numeric" name="album[tracks_attributes][0][number]" pattern="-?[0-9]*" type="text" value="1"/></label>
447
447
  <label>Name: <input id="album_tracks_attributes_0_name" name="album[tracks_attributes][0][name]" type="text" value="Blue Hawaii"/></label>
448
448
  </fieldset>
449
449
  <input id="album_tracks_attributes_1_id" name="album[tracks_attributes][1][id]" type="hidden" value="2"/>
450
450
  <fieldset class="inputs"><legend>Track #2</legend>
451
- <label>Number: <input id="album_tracks_attributes_1_number" name="album[tracks_attributes][1][number]" type="number" value="2"/></label>
451
+ <label>Number: <input id="album_tracks_attributes_1_number" inputmode="numeric" name="album[tracks_attributes][1][number]" pattern="-?[0-9]*" type="text" value="2"/></label>
452
452
  <label>Name: <input id="album_tracks_attributes_1_name" name="album[tracks_attributes][1][name]" type="text" value="Almost Always True"/></label>
453
453
  </fieldset>
454
454
 
@@ -1264,12 +1264,17 @@ You can mark a configuration as the default using:
1264
1264
 
1265
1265
  Forme.default_config = :mine
1266
1266
 
1267
- === Bootstrap 3 Support
1267
+ === Bootstrap Support
1268
1268
 
1269
- Forme ships with support for Bootstrap 3-4 HTML formatting. This support is shipped in
1269
+ Forme ships with support for Bootstrap 5 HTML formatting. This support is shipped in
1270
1270
  it's own file, so if you don't use it, you don't pay the memory penalty for loading
1271
1271
  it.
1272
1272
 
1273
+ require 'forme/bs5'
1274
+ Forme.default_config = :bs5
1275
+
1276
+ There is also support for Bootstrap versions 3-4:
1277
+
1273
1278
  require 'forme/bs3'
1274
1279
  Forme.default_config = :bs3
1275
1280
 
data/lib/forme/bs3.rb CHANGED
@@ -24,6 +24,7 @@ module Forme
24
24
  attr = attr ? attr.dup : {}
25
25
  Forme.attr_classes(attr, 'help-block with-errors')
26
26
  return [tag] if input.opts[:skip_error_message]
27
+ attr[:id] ||= input.opts[:error_id]
27
28
 
28
29
  case input.type
29
30
  when :submit, :reset
@@ -84,11 +85,13 @@ module Forme
84
85
 
85
86
  Forme.attr_classes(@attr, @opts[:class]) if @opts.has_key?(:class)
86
87
 
87
- if @opts[:error]
88
+ if @opts[:error] && input.type != :submit && input.type != :reset
88
89
  # Forme.attr_classes(@attr, 'error')
89
90
  @attr["aria-invalid"] = "true"
90
91
  if @opts.fetch(:error_handler, true)
91
- unless @opts[:error_id]
92
+ if @opts[:error_id]
93
+ @attr['aria-describedby'] ||= @opts[:error_id]
94
+ else
92
95
  if id = @attr[:id] || @attr['id']
93
96
  error_id = @attr['aria-describedby'] ||= "#{id}_error_message"
94
97
  @opts[:error_id] = error_id
@@ -127,7 +130,7 @@ module Forme
127
130
  end
128
131
 
129
132
  def _format_set(type, tag_attrs={})
130
- raise Error, "can't have radioset with no options" unless @opts[:optgroups] || @opts[:options]
133
+ raise Error, "can't have radioset or checkboxset with no options" unless @opts[:optgroups] || @opts[:options]
131
134
  key = @opts[:key]
132
135
  name = @opts[:name]
133
136
  id = @opts[:id]
@@ -282,7 +285,7 @@ module Forme
282
285
  label_attr = input.opts[:label_attr]
283
286
  label_attr = label_attr ? label_attr.dup : {}
284
287
 
285
- label_attr[:for] = label_attr[:for] === false ? nil : input.opts.fetch(:label_for, id)
288
+ label_attr[:for] = label_attr[:for] == false ? nil : input.opts.fetch(:label_for, id)
286
289
  label = input.opts[:label]
287
290
  lpos = input.opts[:label_position] || ([:radio, :checkbox].include?(input.type) ? :after : :before)
288
291
 
@@ -317,9 +320,6 @@ module Forme
317
320
 
318
321
  case input.type
319
322
  when :submit, :reset
320
- klass.delete('form-group')
321
- attr[:class] = klass.sort.uniq.join(' ').strip
322
- attr.delete(:class) if attr[:class].empty?
323
323
  [tag]
324
324
  when :radio, :checkbox
325
325
  klass.delete('form-group')
data/lib/forme/bs5.rb ADDED
@@ -0,0 +1,213 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Forme
4
+ register_config(:bs5, formatter: :bs5, wrapper: :bs5, error_handler: :bs5, serializer: :bs5, labeler: :bs5, helper: :bs5, tag_wrapper: :bs5, set_wrapper: :div)
5
+
6
+ # Update the <tt>:class</tt> entry in the +attr+ hash with the given +classes+,
7
+ # adding the classes before any existing classes.
8
+ def self.attr_classes_after(attr, *classes)
9
+ attr[:class] = merge_classes(*classes, attr[:class])
10
+ end
11
+
12
+ class ErrorHandler::Bootstrap5
13
+ Forme.register_transformer(:error_handler, :bs5, new)
14
+
15
+ def call(tags, input)
16
+ attr = input.opts[:error_attr]
17
+ attr = attr ? attr.dup : {}
18
+
19
+ unless attr[:class] && attr[:class].include?("invalid-tooltip")
20
+ Forme.attr_classes(attr, "invalid-feedback")
21
+ end
22
+
23
+ attr[:id] ||= input.opts[:error_id]
24
+
25
+ [tags, input.tag(:div, attr, input.opts[:error])]
26
+ end
27
+ end
28
+
29
+ class Formatter::Bootstrap5 < Formatter
30
+ Forme.register_transformer(:formatter, :bs5, self)
31
+
32
+ private
33
+
34
+ def normalize_options
35
+ super
36
+
37
+ if @opts[:error]
38
+ # remove "error" class
39
+ @attr[:class] = @attr[:class].to_s.sub(/\s*error$/,'')
40
+ @attr.delete(:class) if @attr[:class].to_s == ''
41
+
42
+ Forme.attr_classes(@attr, "is-invalid")
43
+ end
44
+
45
+ if @opts[:help]
46
+ if @opts[:helper_attr] && @opts[:helper_attr][:id]
47
+ @attr["aria-describedby"] ||= @opts[:helper_attr][:id]
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # Formatter that adds "readonly" for most input types,
54
+ # and disables select/radio/checkbox inputs.
55
+ #
56
+ # Registered as :bs5_readonly.
57
+ class Formatter::Bs5ReadOnly < Formatter
58
+ Forme.register_transformer(:formatter, :bs5_readonly, self)
59
+
60
+ private
61
+
62
+ # Disabled checkbox inputs.
63
+ def format_checkbox
64
+ @attr[:disabled] = :disabled
65
+ super
66
+ end
67
+
68
+ # Use a span with text instead of an input field.
69
+ def _format_input(type)
70
+ @attr[:readonly] = :readonly
71
+ super
72
+ end
73
+
74
+ # Disabled radio button inputs.
75
+ def format_radio
76
+ @attr[:disabled] = :disabled
77
+ super
78
+ end
79
+
80
+ # Use a span with text of the selected values instead of a select box.
81
+ def format_select
82
+ @attr[:disabled] = :disabled
83
+ super
84
+ end
85
+
86
+ # Use a span with text instead of a text area.
87
+ def format_textarea
88
+ @attr[:readonly] = :readonly
89
+ super
90
+ end
91
+ end
92
+
93
+ # Use a <table class="table"> tag to wrap the inputs.
94
+ #
95
+ # Registered as :bs5_table.
96
+ class InputsWrapper::Bs5Table
97
+ Forme.register_transformer(:inputs_wrapper, :bs5_table, new)
98
+
99
+ # Wrap the inputs in a <table> tag.
100
+ def call(form, opts, &block)
101
+ attr = opts[:attr] ? opts[:attr].dup : { :class=>'table table-bordered'}
102
+ form.tag(:table, attr) do
103
+ if legend = opts[:legend]
104
+ form.tag(:caption, opts[:legend_attr], legend)
105
+ end
106
+
107
+ if (labels = opts[:labels]) && !labels.empty?
108
+ form.tag(:tr, {}, labels.map{|l| form._tag(:th, {}, l)})
109
+ end
110
+
111
+ yield
112
+ end
113
+ end
114
+ end
115
+
116
+ class Labeler::Bootstrap5 < Labeler::Explicit
117
+ Forme.register_transformer(:labeler, :bs5, new)
118
+
119
+ def call(tag, input)
120
+ floating_label = (input.opts[:wrapper_attr] || {})[:class].to_s.include?("form-floating")
121
+ input.opts[:label_position] ||= :after if floating_label
122
+
123
+ tags = super
124
+ return tags if floating_label
125
+
126
+ attr = tags.find { |tag| tag.is_a?(Tag) && tag.type == :label }.attr
127
+
128
+ label_class = case input.type
129
+ when :radio, :checkbox
130
+ "form-check-label"
131
+ else
132
+ "form-label"
133
+ end
134
+ Forme.attr_classes_after(attr, label_class)
135
+
136
+ tags
137
+ end
138
+ end
139
+
140
+ class Helper::Bootstrap5
141
+ Forme.register_transformer(:helper, :bs5, new)
142
+
143
+ def call(tag, input)
144
+ attr = input.opts[:helper_attr]
145
+ attr = attr ? attr.dup : {}
146
+ Forme.attr_classes(attr, 'form-text')
147
+ [tag, input.tag(:div, attr, input.opts[:help])]
148
+ end
149
+ end
150
+
151
+ class Wrapper::Bootstrap5 < Wrapper
152
+ Forme.register_transformer(:wrapper, :bs5, new)
153
+
154
+ def call(tag, input)
155
+ attr = input.opts[:wrapper_attr] ? input.opts[:wrapper_attr].dup : { }
156
+
157
+ case input.type
158
+ when :submit, :reset, :hidden
159
+ super
160
+ when :radio, :checkbox
161
+ Forme.attr_classes_after(attr, "form-check")
162
+ input.tag(:div, attr, super)
163
+ else
164
+ input.tag(:div, attr, super)
165
+ end
166
+ end
167
+ end
168
+
169
+ class Serializer::Bootstrap5 < Serializer
170
+ Forme.register_transformer(:serializer, :bs5, new)
171
+
172
+ BUTTON_STYLES = %w[
173
+ btn-primary btn-secondary btn-success btn-danger btn-warning btn-info btn-light btn-dark btn-link
174
+ btn-outline-primary btn-outline-secondary btn-outline-success btn-outline-danger btn-outline-warning btn-outline-info btn-outline-light btn-outline-dark
175
+ ].freeze
176
+
177
+ def call(tag)
178
+ return super unless tag.is_a?(Tag)
179
+
180
+ attr_class = case tag.type
181
+ when :input
182
+ # default to <input type="text"...> if not set
183
+ tag.attr[:type] = :text if tag.attr[:type].nil?
184
+
185
+ case tag.attr[:type].to_sym
186
+ when :checkbox, :radio
187
+ "form-check-input"
188
+ when :range
189
+ "form-range"
190
+ when :color
191
+ %w"form-control form-control-color"
192
+ when :submit, :reset
193
+ classes = ["btn"]
194
+ classes << "btn-primary" if (tag.attr[:class].to_s.split(" ") & BUTTON_STYLES).empty?
195
+ classes
196
+ when :hidden
197
+ # nothing
198
+ else
199
+ unless tag.attr[:class] && tag.attr[:class].include?("form-control-plaintext")
200
+ "form-control"
201
+ end
202
+ end
203
+ when :textarea
204
+ "form-control"
205
+ when :select
206
+ "form-select"
207
+ end
208
+ Forme.attr_classes_after(tag.attr, *attr_class) if attr_class
209
+
210
+ super
211
+ end
212
+ end
213
+ end
data/lib/forme/form.rb CHANGED
@@ -333,7 +333,9 @@ module Forme
333
333
  copy_inputs_wrapper_from_wrapper(opts, @opts)
334
334
  yield
335
335
  ensure
336
+ # :nocov:
336
337
  @opts = orig_opts if orig_opts
338
+ # :nocov:
337
339
  end
338
340
 
339
341
  private
@@ -49,17 +49,17 @@ module Forme
49
49
  Forme.register_transformer(:error_handler, :after_legend, new)
50
50
 
51
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
52
+ if tag.is_a?(Array) && tag.first.is_a?(Tag) && tag.first.type == :legend
53
+ first_input = input.opts[:first_input]
54
+ attr = first_input.opts[:attr] ||= {}
55
+ Forme.attr_classes(attr, 'error')
56
+ attr['aria-invalid'] = 'true'
57
+ attr['aria-describedby'] = input.opts[:error_id] = "#{first_input.opts[:id]}_error_message"
55
58
 
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))
59
+ tag.insert(1, error_tag(input))
60
+ else
61
+ super
62
+ end
63
63
  end
64
64
  end
65
65
  end
@@ -220,7 +220,7 @@ module Forme
220
220
  end
221
221
 
222
222
  def _format_set(type, tag_attrs={})
223
- raise Error, "can't have radioset with no options" unless @opts[:optgroups] || @opts[:options]
223
+ raise Error, "can't have radioset or checkboxset with no options" unless @opts[:optgroups] || @opts[:options]
224
224
  key = @opts[:key]
225
225
  name = @opts[:name]
226
226
  id = @opts[:id]
@@ -312,7 +312,9 @@ module Forme
312
312
  Forme.attr_classes(@attr, 'error')
313
313
  @attr["aria-invalid"] = "true"
314
314
  if @opts.fetch(:error_handler, true)
315
- unless @opts[:error_id]
315
+ if @opts[:error_id]
316
+ @attr['aria-describedby'] ||= @opts[:error_id]
317
+ else
316
318
  if id = @attr[:id] || @attr['id']
317
319
  error_id = @attr['aria-describedby'] ||= "#{id}_error_message"
318
320
  @opts[:error_id] = error_id
@@ -397,9 +399,7 @@ module Forme
397
399
 
398
400
  def set_error_from_namespaced_errors(namespaces, errors, key)
399
401
  namespaces.each do |ns|
400
- e = errors[ns] || errors[ns.to_s]
401
- return unless e
402
- errors = e
402
+ return unless errors = errors[ns] || errors[ns.to_s]
403
403
  end
404
404
 
405
405
  @opts[:error] = errors.fetch(key){errors.fetch(key.to_s){return}}
@@ -432,38 +432,36 @@ module Forme
432
432
  # Iterate over the given options, yielding the option text, value, whether it is selected, and any attributes.
433
433
  # The block should return an appropriate tag object.
434
434
  def process_select_options(os)
435
- if os
436
- vm = @opts[:value_method]
437
- tm = @opts[:text_method]
438
- sel = @opts[:selected] || @attr.delete(:value)
439
-
440
- if @opts[:multiple]
441
- sel = Array(sel)
442
- cmp = lambda{|v| sel.include?(v)}
443
- else
444
- cmp = lambda{|v| v == sel}
445
- end
435
+ vm = @opts[:value_method]
436
+ tm = @opts[:text_method]
437
+ sel = @opts[:selected] || @attr.delete(:value)
446
438
 
447
- os.map do |x|
448
- attr = {}
449
- if tm
450
- text = x.send(tm)
451
- val = x.send(vm) if vm
452
- elsif x.is_a?(Array)
453
- text = x.first
454
- val = x.last
455
-
456
- if val.is_a?(Hash)
457
- value = val[:value]
458
- attr.merge!(val)
459
- val = value
460
- end
461
- else
462
- text = x
463
- end
439
+ if @opts[:multiple]
440
+ sel = Array(sel)
441
+ cmp = lambda{|v| sel.include?(v)}
442
+ else
443
+ cmp = lambda{|v| v == sel}
444
+ end
464
445
 
465
- yield [text, val, !val.nil? ? cmp.call(val) : cmp.call(text), attr]
446
+ os.map do |x|
447
+ attr = {}
448
+ if tm
449
+ text = x.send(tm)
450
+ val = x.send(vm) if vm
451
+ elsif x.is_a?(Array)
452
+ text = x.first
453
+ val = x.last
454
+
455
+ if val.is_a?(Hash)
456
+ value = val[:value]
457
+ attr.merge!(val)
458
+ val = value
459
+ end
460
+ else
461
+ text = x
466
462
  end
463
+
464
+ yield [text, val, !val.nil? ? cmp.call(val) : cmp.call(text), attr]
467
465
  end
468
466
  end
469
467
 
data/lib/forme/version.rb CHANGED
@@ -6,7 +6,7 @@ module Forme
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Forme, updated for new feature releases of Forme.
9
- MINOR = 1
9
+ MINOR = 3
10
10
 
11
11
  # The patch version of Forme, updated only for bug fixes from the last
12
12
  # feature release.
data/lib/forme.rb CHANGED
@@ -96,7 +96,8 @@ module Forme
96
96
  Form.form(*a, &block)
97
97
  end
98
98
 
99
- # Update the <tt>:class</tt> entry in the +attr+ hash with the given +classes+.
99
+ # Update the <tt>:class</tt> entry in the +attr+ hash with the given +classes+,
100
+ # adding the classes after any existing classes.
100
101
  def self.attr_classes(attr, *classes)
101
102
  attr[:class] = merge_classes(attr[:class], *classes)
102
103
  end
@@ -13,7 +13,9 @@ class Roda
13
13
 
14
14
  # Set the HMAC secret.
15
15
  def self.configure(app, opts = OPTS, &block)
16
- app.opts[:forme_set_hmac_secret] = opts[:secret] || app.opts[:forme_set_hmac_secret]
16
+ unless app.opts[:forme_set_hmac_secret] = opts[:secret] || app.opts[:forme_set_hmac_secret]
17
+ raise RodaError, "must provide :secret option to forme_set plugin"
18
+ end
17
19
 
18
20
  if block
19
21
  app.send(:define_method, :_forme_set_handle_error, &block)
@@ -27,8 +29,8 @@ class Roda
27
29
 
28
30
  # Map of error types to error messages
29
31
  ERROR_MESSAGES = {
30
- :missing_data=>"_forme_set_data parameter not submitted",
31
- :missing_hmac=>"_forme_set_data_hmac parameter not submitted",
32
+ :missing_data=>"_forme_set_data parameter not submitted, make sure the forme_set Sequel plugin is loaded",
33
+ :missing_hmac=>"_forme_set_data_hmac parameter not submitted, make sure the forme_set Sequel plugin is loaded",
32
34
  :hmac_mismatch=>"_forme_set_data_hmac does not match _forme_set_data",
33
35
  :csrf_mismatch=>"_forme_set_data CSRF token does not match submitted CSRF token",
34
36
  :missing_namespace=>"no content in expected namespace"
@@ -95,7 +95,7 @@ module Sequel # :nodoc:
95
95
  end
96
96
 
97
97
  if grid
98
- labels = opts.fetch(:labels){opts[:inputs].map{|l, *| humanize(l)} if opts[:inputs]}
98
+ labels = opts.fetch(:labels){opts[:inputs].map{|l,| humanize(l)} if opts[:inputs]}
99
99
  legend = opts.fetch(:legend){humanize(association)}
100
100
  inputs_opts = opts[:inputs_opts] || {}
101
101
  inputs(inputs_opts.merge(:inputs_wrapper=>:table, :nested_inputs_wrapper=>:tr, :wrapper=>:td, :labeler=>nil, :labels=>labels, :legend=>legend), &contents)
@@ -363,9 +363,10 @@ module Sequel # :nodoc:
363
363
  opts[:as] = (sch[:allow_null] || opts[:required] == false) ? :select : :checkbox
364
364
  end
365
365
 
366
+ v = opts.has_key?(:value) ? opts[:value] : obj.send(field)
367
+
366
368
  case opts[:as]
367
369
  when :radio
368
- v = opts.has_key?(:value) ? opts[:value] : obj.send(field)
369
370
  true_value = opts[:true_value]||'t'
370
371
  false_value = opts[:false_value]||'f'
371
372
  opts[:options] = [[opts[:true_label]||'Yes', {:value=>true_value, :key_id=>'yes'}], [opts[:false_label]||'No', {:value=>false_value, :key_id=>'no'}]]
@@ -374,13 +375,12 @@ module Sequel # :nodoc:
374
375
  end
375
376
  _input(:radioset, opts)
376
377
  when :select
377
- v = opts[:value] || obj.send(field)
378
378
  opts[:value] = (v ? 't' : 'f') unless v.nil?
379
379
  opts[:add_blank] = true unless opts.has_key?(:add_blank)
380
380
  opts[:options] = [[opts[:true_label]||'True', opts[:true_value]||'t'], [opts[:false_label]||'False', opts[:false_value]||'f']]
381
381
  _input(:select, opts)
382
382
  else
383
- opts[:checked] = obj.send(field)
383
+ opts[:checked] = v
384
384
  opts[:value] = 't'
385
385
  _input(:checkbox, opts)
386
386
  end
@@ -424,9 +424,11 @@ module Sequel # :nodoc:
424
424
  end
425
425
  end
426
426
 
427
- # Use number inputs for integers.
427
+ # Use inputmode and pattern attributes for integers.
428
428
  def input_integer(sch)
429
- standard_input(:number)
429
+ opts[:attr][:inputmode] ||= 'numeric'
430
+ opts[:attr][:pattern] ||= '-?[0-9]*'
431
+ standard_input(:text)
430
432
  end
431
433
 
432
434
  # Use date inputs for dates.
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../../forme'
4
+
3
5
  module Sequel # :nodoc:
4
6
  module Plugins # :nodoc:
5
7
  # The forme_set plugin makes the model instance keep track of which form
@@ -105,10 +107,8 @@ module Sequel # :nodoc:
105
107
  opts = input.opts
106
108
  return if SKIP_FORMATTERS.include?(opts.fetch(:formatter){input.form_opts[:formatter]})
107
109
 
108
- if attr = opts[:attr]
109
- name = attr[:name] || attr['name']
110
- end
111
- return unless name ||= opts[:name] || opts[:key]
110
+ attr = opts[:attr] || {}
111
+ return unless name ||= attr[:name] || attr['name'] || opts[:name] || opts[:key]
112
112
 
113
113
  # Pull out last component of the name if there is one
114
114
  column = name.to_s.chomp('[]')
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: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-25 00:00:00.000000000 Z
11
+ date: 2022-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -157,6 +157,7 @@ description: |
157
157
  2) Have a simple API
158
158
  3) Support forms both with and without related objects
159
159
  4) Allow compiling down to different types of output
160
+ 5) Integrate easily into web frameworks
160
161
  email: code@jeremyevans.net
161
162
  executables: []
162
163
  extensions: []
@@ -168,9 +169,9 @@ files:
168
169
  - CHANGELOG
169
170
  - MIT-LICENSE
170
171
  - README.rdoc
171
- - Rakefile
172
172
  - lib/forme.rb
173
173
  - lib/forme/bs3.rb
174
+ - lib/forme/bs5.rb
174
175
  - lib/forme/erb.rb
175
176
  - lib/forme/form.rb
176
177
  - lib/forme/input.rb
@@ -193,24 +194,6 @@ files:
193
194
  - lib/sequel/plugins/forme.rb
194
195
  - lib/sequel/plugins/forme_i18n.rb
195
196
  - lib/sequel/plugins/forme_set.rb
196
- - spec/all.rb
197
- - spec/bs3_reference_spec.rb
198
- - spec/bs3_sequel_plugin_spec.rb
199
- - spec/bs3_spec.rb
200
- - spec/erb_helper.rb
201
- - spec/erubi_capture_helper.rb
202
- - spec/forme_coverage.rb
203
- - spec/forme_spec.rb
204
- - spec/rails_integration_spec.rb
205
- - spec/roda_integration_spec.rb
206
- - spec/sequel_helper.rb
207
- - spec/sequel_i18n_helper.rb
208
- - spec/sequel_i18n_plugin_spec.rb
209
- - spec/sequel_plugin_spec.rb
210
- - spec/sequel_set_plugin_spec.rb
211
- - spec/shared_erb_specs.rb
212
- - spec/sinatra_integration_spec.rb
213
- - spec/spec_helper.rb
214
197
  homepage: http://github.com/jeremyevans/forme
215
198
  licenses:
216
199
  - MIT
@@ -220,7 +203,7 @@ metadata:
220
203
  documentation_uri: http://forme.jeremyevans.net
221
204
  mailing_list_uri: https://github.com/jeremyevans/forme/discussions
222
205
  source_code_uri: https://github.com/jeremyevans/forme
223
- post_install_message:
206
+ post_install_message:
224
207
  rdoc_options:
225
208
  - "--quiet"
226
209
  - "--line-numbers"
@@ -243,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
226
  version: '0'
244
227
  requirements: []
245
228
  rubygems_version: 3.3.7
246
- signing_key:
229
+ signing_key:
247
230
  specification_version: 4
248
231
  summary: HTML forms library
249
232
  test_files: []