roda-tags 0.1.1
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 +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +24 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +1083 -0
- data/Rakefile +21 -0
- data/lib/core_ext/blank.rb +158 -0
- data/lib/core_ext/hash.rb +47 -0
- data/lib/core_ext/object.rb +31 -0
- data/lib/core_ext/string.rb +330 -0
- data/lib/roda/plugins/tag_helpers.rb +919 -0
- data/lib/roda/plugins/tags.rb +452 -0
- data/lib/roda/tags.rb +3 -0
- data/lib/roda/tags/version.rb +8 -0
- data/roda-tags.gemspec +49 -0
- metadata +237 -0
|
@@ -0,0 +1,919 @@
|
|
|
1
|
+
require 'roda'
|
|
2
|
+
require_relative '../../core_ext/string' unless ''.respond_to?(:titleize)
|
|
3
|
+
# require_relative '../../core_ext/object' unless :symbol.respond_to?(:in?)
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
module RodaPlugins
|
|
9
|
+
|
|
10
|
+
# TODO: add documentation here
|
|
11
|
+
module RodaTagHelpers
|
|
12
|
+
# default options
|
|
13
|
+
OPTS = {
|
|
14
|
+
#
|
|
15
|
+
tags_label_required_str: '<span>*</span>',
|
|
16
|
+
#
|
|
17
|
+
tags_label_append_str: ':',
|
|
18
|
+
# the default classes for various form tags. ie: shortcut to automatically add
|
|
19
|
+
# BS3 'form-control'
|
|
20
|
+
tags_forms_default_class: '', # 'form-control',
|
|
21
|
+
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Depend on the render plugin, since this plugin only makes
|
|
26
|
+
# sense when the render plugin is used.
|
|
27
|
+
def self.load_dependencies(app, opts = OPTS)
|
|
28
|
+
app.plugin :tags, opts
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.configure(app, opts = {})
|
|
32
|
+
if app.opts[:tag_helpers]
|
|
33
|
+
opts = app.opts[:tag_helpers][:orig_opts].merge(opts)
|
|
34
|
+
else
|
|
35
|
+
opts = OPTS.merge(opts)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
app.opts[:tag_helpers] = opts.dup
|
|
39
|
+
app.opts[:tag_helpers][:orig_opts] = opts
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
module ClassMethods
|
|
44
|
+
# Return the uitags options for this class.
|
|
45
|
+
def tag_helpers_opts
|
|
46
|
+
opts[:tag_helpers]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
module InstanceMethods
|
|
53
|
+
|
|
54
|
+
# Constructs a form without object based on options
|
|
55
|
+
#
|
|
56
|
+
# ==== Examples
|
|
57
|
+
#
|
|
58
|
+
# form_tag('/register') do
|
|
59
|
+
# ...
|
|
60
|
+
# end
|
|
61
|
+
# #=>
|
|
62
|
+
# <form action="/register" id="register-form" method="post">
|
|
63
|
+
# ...
|
|
64
|
+
# </form>
|
|
65
|
+
#
|
|
66
|
+
#
|
|
67
|
+
# <% form_tag('/register', method: :put, id: 'register-form' ) %>
|
|
68
|
+
# ...
|
|
69
|
+
# <% end %>
|
|
70
|
+
# #=>
|
|
71
|
+
# <form action="/register" id="register-form" method="post" >
|
|
72
|
+
# <input name="_method" type="hidden" value="put"/>
|
|
73
|
+
# ...
|
|
74
|
+
# </form>
|
|
75
|
+
#
|
|
76
|
+
# Multipart support via:
|
|
77
|
+
#
|
|
78
|
+
# <% form_tag('/register', multipart: true ) %>
|
|
79
|
+
#
|
|
80
|
+
# <% form_tag('/register', multipart: 'multipart/form-data' ) %>
|
|
81
|
+
#
|
|
82
|
+
# <% form_tag('/register', enctype: 'multipart/form-data' ) %>
|
|
83
|
+
# #=>
|
|
84
|
+
# <form enctype="multipart/form-data" method="post" action="/register">
|
|
85
|
+
# ...
|
|
86
|
+
# </form>
|
|
87
|
+
#
|
|
88
|
+
def form_tag(action, attrs = {}, &block)
|
|
89
|
+
attrs.reverse_merge!(method: :post, action: action)
|
|
90
|
+
method = attrs[:method]
|
|
91
|
+
# Unless the method is :get, fake out the method using :post
|
|
92
|
+
attrs[:method] = :post unless attrs[:method] == :get
|
|
93
|
+
faux_method_tag = method.to_s =~ /post|get/ ? '' : faux_method(method)
|
|
94
|
+
# set the enctype to multipart-form if we got a @multipart form
|
|
95
|
+
attrs[:enctype] = 'multipart/form-data' if attrs.delete(:multipart) || @multipart
|
|
96
|
+
captured_html = block_given? ? capture_html(&block) : ''
|
|
97
|
+
concat_content(tag(:form, faux_method_tag + captured_html, attrs))
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Constructs a label tag from the given options
|
|
101
|
+
#
|
|
102
|
+
# ==== Examples
|
|
103
|
+
#
|
|
104
|
+
# <%= label_tag(:name) %>
|
|
105
|
+
# #=> <label for="name">Name:</label>
|
|
106
|
+
#
|
|
107
|
+
# Should accept a custom label text.
|
|
108
|
+
#
|
|
109
|
+
# <%= label_tag(:name, label: 'Custom label') %>
|
|
110
|
+
# #=> <label for="name">Custom label:</label>
|
|
111
|
+
#
|
|
112
|
+
# If label value is nil, then renders the default label text.
|
|
113
|
+
#
|
|
114
|
+
# <%= label_tag(:name, label: nil) %>
|
|
115
|
+
# #=> <label for="name">Name:</label>
|
|
116
|
+
#
|
|
117
|
+
# Removes the label text when given :false.
|
|
118
|
+
#
|
|
119
|
+
# <%= label_tag(:name, label: false) %>
|
|
120
|
+
# #=> <label for="name"></label>
|
|
121
|
+
#
|
|
122
|
+
# Appends the <tt>app.forms_label_required_str</tt> value, when the label is required.
|
|
123
|
+
#
|
|
124
|
+
# <%= label_tag(:name, required: true) %>
|
|
125
|
+
# #=> <label for="name">Name: <span>*</span></label>
|
|
126
|
+
#
|
|
127
|
+
def label_tag(field, attrs = {}, &block)
|
|
128
|
+
attrs.reverse_merge!(label: field.to_s.titleize, for: field)
|
|
129
|
+
|
|
130
|
+
label_text = attrs.delete(:label)
|
|
131
|
+
# handle FALSE & nil values
|
|
132
|
+
label_text = '' if label_text == false
|
|
133
|
+
label_text = field.to_s.titleize if label_text.nil?
|
|
134
|
+
|
|
135
|
+
unless label_text.to_s.empty?
|
|
136
|
+
label_text << opts_tag_helpers[:tags_label_append_str]
|
|
137
|
+
if attrs.delete(:required)
|
|
138
|
+
label_text = "#{label_text} #{opts_tag_helpers[:tags_label_required_str]}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if block_given? # label with inner content
|
|
143
|
+
label_content = label_text + capture_html(&block)
|
|
144
|
+
concat_content(tag(:label, label_content, attrs))
|
|
145
|
+
else # regular label
|
|
146
|
+
tag(:label, label_text, attrs)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Constructs a hidden field input from the given options
|
|
151
|
+
#
|
|
152
|
+
# ==== Examples
|
|
153
|
+
#
|
|
154
|
+
# <%= hidden_field_tag(:snippet_name) %>
|
|
155
|
+
# #=>
|
|
156
|
+
# <input id="snippet_name" name="snippet_name" type="hidden">
|
|
157
|
+
#
|
|
158
|
+
# Providing a value:
|
|
159
|
+
#
|
|
160
|
+
# <%= hidden_field_tag(:snippet_name, value: 'myvalue') %>
|
|
161
|
+
# #=>
|
|
162
|
+
# <input id="snippet_name" name="snippet_name" type="hidden" value="myvalue">
|
|
163
|
+
#
|
|
164
|
+
# Setting a different <tt>:id</tt>
|
|
165
|
+
#
|
|
166
|
+
# <%= hidden_field_tag(:snippet_name, id: 'some-id') %>
|
|
167
|
+
# #=>
|
|
168
|
+
# <input id="some-id" name="snippet_name" type="hidden">
|
|
169
|
+
#
|
|
170
|
+
# Removing the <tt>:id</tt> attribute completely.
|
|
171
|
+
#
|
|
172
|
+
# <%= hidden_field_tag(:snippet_name, id: false ) %>
|
|
173
|
+
# #=>
|
|
174
|
+
# <input name="snippet_name" type="hidden">
|
|
175
|
+
#
|
|
176
|
+
def hidden_field_tag(name, attrs = {})
|
|
177
|
+
attrs.reverse_merge!(name: name, value: '', type: :hidden)
|
|
178
|
+
attrs = add_css_id(attrs, name)
|
|
179
|
+
tag(:input, attrs)
|
|
180
|
+
end
|
|
181
|
+
alias_method :hiddenfield_tag, :hidden_field_tag
|
|
182
|
+
|
|
183
|
+
# Creates a standard text field; use these text fields to input smaller chunks of text like
|
|
184
|
+
# a username or a search query.
|
|
185
|
+
#
|
|
186
|
+
# ==== Examples
|
|
187
|
+
#
|
|
188
|
+
# text_field_tag(:snippet_name)
|
|
189
|
+
# #=>
|
|
190
|
+
# <input class="text" id="snippet_name" name="snippet_name" type="text">
|
|
191
|
+
#
|
|
192
|
+
# Providing a value:
|
|
193
|
+
#
|
|
194
|
+
# text_field_tag(:snippet, value: 'some-value')
|
|
195
|
+
# #=>
|
|
196
|
+
# <input class="text" id="snippet" name="snippet" type="text" value="some-value">
|
|
197
|
+
#
|
|
198
|
+
# Setting a different <tt>:id</tt>
|
|
199
|
+
#
|
|
200
|
+
# text_field_tag(:snippet_name, id: 'some-id')
|
|
201
|
+
# #=>
|
|
202
|
+
# <input class="text" id="some-id" name="snippet_name" type="text">
|
|
203
|
+
#
|
|
204
|
+
# Removing the <tt>:id</tt> attribute completely. NB! bad practice.
|
|
205
|
+
#
|
|
206
|
+
# text_field_tag(:snippet_name, id: false)
|
|
207
|
+
# #=>
|
|
208
|
+
# <input class="text" name="snippet_name" type="text">
|
|
209
|
+
#
|
|
210
|
+
# Adding another CSS class. NB! appends the the class to the default class <tt>.text</tt>.
|
|
211
|
+
#
|
|
212
|
+
# text_field_tag(:snippet_name, class: :big )
|
|
213
|
+
# #=>
|
|
214
|
+
# <input class="big text" id="snippet_name" name="snippet_name" type="text">
|
|
215
|
+
#
|
|
216
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
217
|
+
#
|
|
218
|
+
# text_field_tag(:name, ui_hint: 'a user hint')
|
|
219
|
+
# #=>
|
|
220
|
+
# <input class="text" id="name" name="name" title="a user hint" type="text">
|
|
221
|
+
#
|
|
222
|
+
# Supports <tt>:maxlength</tt> & <tt>:size</tt> attributes.
|
|
223
|
+
#
|
|
224
|
+
# text_field_tag(:ip, maxlength: 15, size: 20)
|
|
225
|
+
# #=>
|
|
226
|
+
# <input class="text" id="ip" maxlength="15" name="ip" size="20" type="text">
|
|
227
|
+
#
|
|
228
|
+
# Supports <tt>:disabled</tt> & <tt>:readonly</tt> attributes.
|
|
229
|
+
#
|
|
230
|
+
# text_field_tag(:name, disabled: true)
|
|
231
|
+
# #=>
|
|
232
|
+
# <input class="text" disabled="disabled" id="name" name="name" type="text" >
|
|
233
|
+
#
|
|
234
|
+
# text_field_tag(:name, readonly: true)
|
|
235
|
+
# #=>
|
|
236
|
+
# <input class="text" id="name" name="name" readonly="readonly" type="text">
|
|
237
|
+
#
|
|
238
|
+
#
|
|
239
|
+
def text_field_tag(name, attrs = {})
|
|
240
|
+
attrs.reverse_merge!(name: name, type: :text)
|
|
241
|
+
attrs = add_css_id(attrs, name)
|
|
242
|
+
attrs = add_css_class(attrs, :text)
|
|
243
|
+
attrs = add_ui_hint(attrs)
|
|
244
|
+
tag(:input, attrs)
|
|
245
|
+
end
|
|
246
|
+
alias_method :textfield_tag, :text_field_tag
|
|
247
|
+
|
|
248
|
+
# Constructs a password field input from the given options
|
|
249
|
+
#
|
|
250
|
+
# ==== Examples
|
|
251
|
+
#
|
|
252
|
+
# password_field_tag(:snippet_name)
|
|
253
|
+
# #=> <input class="text" id="snippet_name" name="snippet_name" type="password">
|
|
254
|
+
#
|
|
255
|
+
# Providing a value:
|
|
256
|
+
#
|
|
257
|
+
# password_field_tag(:snippet_name, value: 'some-value')
|
|
258
|
+
# #=>
|
|
259
|
+
# <input class="text" id="snippet" name="snippet" type="password" value="some-value">
|
|
260
|
+
#
|
|
261
|
+
# Setting a different <tt>:id</tt>
|
|
262
|
+
#
|
|
263
|
+
# password_field_tag(:snippet_name, id: 'some-id')
|
|
264
|
+
# #=> <input class="text" id="some-id" name="snippet_name" type="password">
|
|
265
|
+
#
|
|
266
|
+
# Removing the <tt>:id</tt> attribute completely. NB! bad practice.
|
|
267
|
+
#
|
|
268
|
+
# password_field_tag(:snippet_name, id: false)
|
|
269
|
+
# #=> <input class="text" name="snippet_name" type="password">
|
|
270
|
+
#
|
|
271
|
+
# Adding another CSS class. NB! appends the the class to the default class <tt>.text</tt>.
|
|
272
|
+
#
|
|
273
|
+
# password_field_tag(:snippet_name, class: :big )
|
|
274
|
+
# #=> <input class="big text" id="snippet_name" name="snippet_name" type="password">
|
|
275
|
+
#
|
|
276
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
277
|
+
#
|
|
278
|
+
# password_field_tag(:name, ui_hint: 'a user hint')
|
|
279
|
+
# #=> <input class="text" id="name" name="name" title="a user hint" type="password">
|
|
280
|
+
#
|
|
281
|
+
# Supports <tt>:maxlength</tt>, <tt>:size</tt> & <tt>:disabled</tt> attributes.
|
|
282
|
+
#
|
|
283
|
+
# password_field_tag(:ip, maxlength: 15, size: 20)
|
|
284
|
+
# #=> <input class="text" id="ip" maxlength="15" name="ip" size="20" type="password">
|
|
285
|
+
#
|
|
286
|
+
# password_field_tag(:name, disabled: true)
|
|
287
|
+
# #=> <input class="text" id="name" disabled="disabled" name="name" type="password">
|
|
288
|
+
#
|
|
289
|
+
def password_field_tag(name, attrs = {})
|
|
290
|
+
attrs.reverse_merge!(name: name, type: :password)
|
|
291
|
+
attrs = add_css_id(attrs, name)
|
|
292
|
+
attrs = add_css_class(attrs, :text) # deliberately giving it the .text class
|
|
293
|
+
attrs = add_ui_hint(attrs)
|
|
294
|
+
tag(:input, attrs)
|
|
295
|
+
end
|
|
296
|
+
alias_method :passwordfield_tag, :password_field_tag
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Creates a file upload field. If you are using file uploads then you will also
|
|
300
|
+
# need to set the multipart option for the form tag:
|
|
301
|
+
#
|
|
302
|
+
# <% form_tag '/upload', :multipart => true do %>
|
|
303
|
+
# <label for="file">File to Upload</label>
|
|
304
|
+
# <%= file_field_tag "file" %>
|
|
305
|
+
# <%= submit_tag %>
|
|
306
|
+
# <% end %>
|
|
307
|
+
#
|
|
308
|
+
# The specified URL will then be passed a File object containing the selected file,
|
|
309
|
+
# or if the field was left blank, a StringIO object.
|
|
310
|
+
#
|
|
311
|
+
# ==== Examples
|
|
312
|
+
#
|
|
313
|
+
# file_field_tag('attachment')
|
|
314
|
+
# #=> <input class="file" id="attachment" name="attachment" type="file">
|
|
315
|
+
#
|
|
316
|
+
# Ignores the invalid <tt>:value</tt> attribute.
|
|
317
|
+
#
|
|
318
|
+
# file_field_tag(:photo, value: 'some-value')
|
|
319
|
+
# #=> <input class="file" id="photo" name="photo" type="file">
|
|
320
|
+
#
|
|
321
|
+
# Setting a different <tt>:id</tt>
|
|
322
|
+
#
|
|
323
|
+
# file_field_tag(:photo, id: 'some-id')
|
|
324
|
+
# #=> <input class="file" id="some-id" name="photo" type="file">
|
|
325
|
+
#
|
|
326
|
+
# Removing the <tt>:id</tt> attribute completely. NB! bad practice.
|
|
327
|
+
#
|
|
328
|
+
# file_field_tag(:photo, id: false)
|
|
329
|
+
# #=> <input class="file" name="photo" type="file">
|
|
330
|
+
#
|
|
331
|
+
# Adding another CSS class. NB! appends the the class to the default class +.text+.
|
|
332
|
+
#
|
|
333
|
+
# file_field_tag(:photo, class: :big )
|
|
334
|
+
# #=> <input class="big file" id="photo" name="photo" type="file">
|
|
335
|
+
#
|
|
336
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>. Also works with +:title+.
|
|
337
|
+
#
|
|
338
|
+
# file_field_tag(:photo, ui_hint: 'a user hint')
|
|
339
|
+
# #=> <input class="file" id="photo" name="photo" title="a user hint" type="file">
|
|
340
|
+
#
|
|
341
|
+
# Supports the <tt>:disabled</tt> attribute.
|
|
342
|
+
#
|
|
343
|
+
# file_field_tag(:photo, disabled: true)
|
|
344
|
+
# #=> <input class="file" disabled="disabled" id="photo" name="photo" type="file">
|
|
345
|
+
#
|
|
346
|
+
#
|
|
347
|
+
# Supports the <tt>:accept</tt> attribute, even though most browsers don't.
|
|
348
|
+
#
|
|
349
|
+
# file_field_tag(:photo, accept: 'image/png,image/jpeg')
|
|
350
|
+
# #=>
|
|
351
|
+
# <input accept="image/png,image/jpeg" class="file" ... type="file">
|
|
352
|
+
#
|
|
353
|
+
def file_field_tag(name, attrs = {})
|
|
354
|
+
attrs.reverse_merge!(name: name, type: :file)
|
|
355
|
+
attrs.delete(:value) # can't use value, so delete it if present
|
|
356
|
+
attrs = add_css_id(attrs, name)
|
|
357
|
+
attrs = add_css_class(attrs, :file)
|
|
358
|
+
attrs = add_ui_hint(attrs)
|
|
359
|
+
tag(:input, attrs)
|
|
360
|
+
end
|
|
361
|
+
alias_method :filefield_tag, :file_field_tag
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# Constructs a textarea input from the given options
|
|
365
|
+
#
|
|
366
|
+
# TODO: enable :escape functionality...
|
|
367
|
+
#
|
|
368
|
+
# * <tt>:escape</tt> - By default, the contents of the text input are HTML escaped. If you
|
|
369
|
+
# need unescaped contents, set this to false.
|
|
370
|
+
#
|
|
371
|
+
# Any other key creates standard HTML attributes for the tag.
|
|
372
|
+
#
|
|
373
|
+
# ==== Examples
|
|
374
|
+
#
|
|
375
|
+
# textarea_tag('post')
|
|
376
|
+
# #=> <textarea id="post" name="post">\n</textarea>
|
|
377
|
+
#
|
|
378
|
+
# Providing a value:
|
|
379
|
+
#
|
|
380
|
+
# textarea_tag(:bio, value: @actor.bio)
|
|
381
|
+
# #=> <textarea id="bio" name="bio">This is my biography.\n</textarea>
|
|
382
|
+
#
|
|
383
|
+
# Setting a different <tt>:id</tt>
|
|
384
|
+
#
|
|
385
|
+
# textarea_tag(:body, id: 'some-id')
|
|
386
|
+
# #=> <textarea id="some-id" name="post">\n\n</textarea>
|
|
387
|
+
#
|
|
388
|
+
# Adding a CSS class. NB! textarea has no other class by default.
|
|
389
|
+
#
|
|
390
|
+
# textarea_tag(:body, class: 'big')
|
|
391
|
+
# #=> <textarea class="big" id="post" name="post">\n</textarea>
|
|
392
|
+
#
|
|
393
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
394
|
+
#
|
|
395
|
+
# textarea_tag(:body, ui_hint: 'a user hint')
|
|
396
|
+
# #=> <textarea id="post" name="post" title="a user hint">\n</textarea>
|
|
397
|
+
#
|
|
398
|
+
# Supports <tt>:rows</tt> & <tt>:cols</tt> attributes.
|
|
399
|
+
#
|
|
400
|
+
# textarea_tag('body', rows: 10, cols: 25)
|
|
401
|
+
# #=> <textarea cols="25" id="body" name="body" rows="10">\n</textarea>
|
|
402
|
+
#
|
|
403
|
+
# Supports shortcut to +:rows+ & +:cols+ attributes, via the +:size+ attribute.
|
|
404
|
+
#
|
|
405
|
+
# textarea_tag( 'body', size: "25x10")
|
|
406
|
+
# #=> <textarea cols="25" id="body" name="body" rows="10"></textarea>
|
|
407
|
+
#
|
|
408
|
+
# Supports +:disabled+ & +:readonly+ attributes.
|
|
409
|
+
#
|
|
410
|
+
# textarea_tag(:description, disabled: true)
|
|
411
|
+
# #=> <textarea disabled="disabled" id="description" name="description"></textarea>
|
|
412
|
+
#
|
|
413
|
+
# textarea_tag(:description, readonly: true)
|
|
414
|
+
# #=> <textarea id="description" name="description" readonly="readonly"></textarea>
|
|
415
|
+
#
|
|
416
|
+
def textarea_tag(name, attrs = {})
|
|
417
|
+
attrs.reverse_merge!(name: name)
|
|
418
|
+
attrs = add_css_id(attrs, name)
|
|
419
|
+
if size = attrs.delete(:size)
|
|
420
|
+
attrs[:cols], attrs[:rows] = size.split('x') if size.respond_to?(:split)
|
|
421
|
+
end
|
|
422
|
+
content = attrs.delete(:value)
|
|
423
|
+
attrs = add_ui_hint(attrs)
|
|
424
|
+
tag(:textarea, content, attrs)
|
|
425
|
+
end
|
|
426
|
+
alias_method :text_area_tag, :textarea_tag
|
|
427
|
+
|
|
428
|
+
# Creates a field set for grouping HTML form elements.
|
|
429
|
+
#
|
|
430
|
+
# ==== Examples
|
|
431
|
+
#
|
|
432
|
+
# <% field_set_tag(:actor) %>
|
|
433
|
+
# #=>
|
|
434
|
+
# <fieldset id="fieldset-actor">
|
|
435
|
+
# ...
|
|
436
|
+
# </fieldset>
|
|
437
|
+
#
|
|
438
|
+
# Sets the <tt><legend></tt> and <tt>:id</tt> attribute when given a single argument.
|
|
439
|
+
#
|
|
440
|
+
# <% field_set_tag 'User Details' do %>
|
|
441
|
+
# <p><%= text_field_tag 'name' %></p>
|
|
442
|
+
# <% end %>
|
|
443
|
+
# #=>
|
|
444
|
+
# <fieldset id="fieldset-user-details">
|
|
445
|
+
# <legend>User Details</legend>
|
|
446
|
+
# <p><input name="name" class="text" id="name" type="text"></p>
|
|
447
|
+
# </fieldset>
|
|
448
|
+
#
|
|
449
|
+
# Supports <tt>:legend</tt> attribute for the <tt><legend></tt> tag.
|
|
450
|
+
#
|
|
451
|
+
# field_set_tag(:actor, legend: 'Your Details')
|
|
452
|
+
# #=>
|
|
453
|
+
# <fieldset id="fieldset-actor">
|
|
454
|
+
# <legend>Your Details</legend>
|
|
455
|
+
# <snip...>
|
|
456
|
+
#
|
|
457
|
+
# Adding a CSS class. NB! fieldset has no other class by default.
|
|
458
|
+
#
|
|
459
|
+
# field_set_tag(:actor, class: "legend-class")
|
|
460
|
+
# #=>
|
|
461
|
+
# <fieldset class="legend-class" id="fieldset-actor">
|
|
462
|
+
# <snip...>
|
|
463
|
+
#
|
|
464
|
+
#
|
|
465
|
+
# When passed +nil+ as the first argument the <tt>:id</tt> becomes 'fieldset'.
|
|
466
|
+
#
|
|
467
|
+
# field_set_tag( nil, class: 'format')
|
|
468
|
+
# #=>
|
|
469
|
+
# <fieldset class="format" id="fieldset">
|
|
470
|
+
# <snip...>
|
|
471
|
+
#
|
|
472
|
+
# Removing the <tt>:id</tt> attribute completely.
|
|
473
|
+
#
|
|
474
|
+
# field_set_tag('User Details', id: false)
|
|
475
|
+
# #=>
|
|
476
|
+
# <fieldset>
|
|
477
|
+
# <legend>User Details</legend>
|
|
478
|
+
# <snip...>
|
|
479
|
+
#
|
|
480
|
+
# @api public
|
|
481
|
+
def field_set_tag(*args, &block)
|
|
482
|
+
attrs = args.last.is_a?(Hash) ? args.pop : {}
|
|
483
|
+
attrs = add_css_id(attrs, ['fieldset', args.first].compact.join('-'))
|
|
484
|
+
legend_text = args.first.is_a?(String || Symbol) ? args.first : attrs.delete(:legend)
|
|
485
|
+
legend_html = legend_text.blank? ? '' : tag(:legend, legend_text)
|
|
486
|
+
captured_html = block_given? ? capture_html(&block) : ''
|
|
487
|
+
concat_content(tag(:fieldset, legend_html + captured_html, attrs))
|
|
488
|
+
end
|
|
489
|
+
alias_method :fieldset_tag, :field_set_tag
|
|
490
|
+
|
|
491
|
+
# Return a legend with _contents_.
|
|
492
|
+
#
|
|
493
|
+
# ==== Examples
|
|
494
|
+
#
|
|
495
|
+
# legend_tag('User Details')
|
|
496
|
+
# #=> <legend>User Details</legend>
|
|
497
|
+
#
|
|
498
|
+
# Adding an :id attribute.
|
|
499
|
+
#
|
|
500
|
+
# legend_tag('User Details', id: 'some-id')
|
|
501
|
+
# #=> <legend id="some-id">User Details</legend>
|
|
502
|
+
#
|
|
503
|
+
# Adding a CSS class. NB! legend has no other class by default.
|
|
504
|
+
#
|
|
505
|
+
# legend_tag('User Details', class: 'some-class')
|
|
506
|
+
# #=> <legend class="some-class">User Details</legend>
|
|
507
|
+
#
|
|
508
|
+
def legend_tag(contents, attrs = {})
|
|
509
|
+
tag(:legend, contents, attrs)
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# Creates a checkbox element.
|
|
513
|
+
#
|
|
514
|
+
# ==== Examples
|
|
515
|
+
#
|
|
516
|
+
# check_box_tag(:accept)
|
|
517
|
+
# #=> <input class="checkbox" id="accept" name="accept" type="checkbox" value="1">
|
|
518
|
+
#
|
|
519
|
+
# Providing a value:
|
|
520
|
+
#
|
|
521
|
+
# check_box_tag(:rock, value: 'rock music')
|
|
522
|
+
# #=> <input class="checkbox" id="rock" name="rock" type="checkbox" value="rock music">
|
|
523
|
+
#
|
|
524
|
+
# Setting a different <tt>:id</tt>.
|
|
525
|
+
#
|
|
526
|
+
# check_box_tag(:rock, :id => 'some-id')
|
|
527
|
+
# #=> <input class="checkbox" id="some-id" name="rock" type="checkbox" value="1">
|
|
528
|
+
#
|
|
529
|
+
# Adding another CSS class. NB! appends the the class to the default class +.checkbox+.
|
|
530
|
+
#
|
|
531
|
+
# check_box_tag(:rock, class: 'small')
|
|
532
|
+
# #=> <input class="small checkbox" id="rock" name="rock" type="checkbox" value="1">
|
|
533
|
+
#
|
|
534
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
535
|
+
#
|
|
536
|
+
# check_box_tag(:rock, ui_hint: 'a user hint')
|
|
537
|
+
# #=> <input ... title="a user hint" type="checkbox" value="1">
|
|
538
|
+
#
|
|
539
|
+
# Supports the <tt>:disabled</tt> & <tt>:checked</tt> attributes.
|
|
540
|
+
#
|
|
541
|
+
# check_box_tag(:rock, checked: true)
|
|
542
|
+
# #=> <input checked="checked" ... type="checkbox" value="1">
|
|
543
|
+
#
|
|
544
|
+
# check_box_tag(:rock, disabled: true)
|
|
545
|
+
# #=> <input class="checkbox" disabled="disabled" ... type="checkbox" value="1">
|
|
546
|
+
#
|
|
547
|
+
def check_box_tag(name, attrs = {})
|
|
548
|
+
attrs.reverse_merge!(name: name, type: :checkbox, checked: false, value: 1)
|
|
549
|
+
attrs = add_css_id(attrs, name)
|
|
550
|
+
attrs = add_css_class(attrs, :checkbox)
|
|
551
|
+
attrs = add_ui_hint(attrs)
|
|
552
|
+
tag(:input, attrs)
|
|
553
|
+
end
|
|
554
|
+
alias_method :checkbox_tag, :check_box_tag
|
|
555
|
+
|
|
556
|
+
# Creates a radio button; use groups of radio buttons named the same to allow users to
|
|
557
|
+
# select from a group of options.
|
|
558
|
+
#
|
|
559
|
+
# ==== Examples
|
|
560
|
+
#
|
|
561
|
+
# radio_button_tag(:accept)
|
|
562
|
+
# #=> <input class="radio" id="accept_1" name="accept" type="radio" value="1">
|
|
563
|
+
#
|
|
564
|
+
# Providing a value:
|
|
565
|
+
#
|
|
566
|
+
# radio_button_tag(:rock, value: 'rock music')
|
|
567
|
+
# #=> <input ... type="radio" value="rock music">
|
|
568
|
+
#
|
|
569
|
+
# Setting a different <tt>:id</tt>.
|
|
570
|
+
#
|
|
571
|
+
# radio_button_tag(:rock, id: 'some-id')
|
|
572
|
+
# #=>
|
|
573
|
+
# <input class="radio" id="some-id_1" name="rock" type="radio" value="1">
|
|
574
|
+
#
|
|
575
|
+
# Adding another CSS class. NB! appends the the class to the default class +.radio+.
|
|
576
|
+
#
|
|
577
|
+
# radio_button_tag(:rock, class: 'big')
|
|
578
|
+
# #=> <input class="big radio" id="rock_1" name="rock" type="radio" value="1">
|
|
579
|
+
#
|
|
580
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
581
|
+
#
|
|
582
|
+
# radio_button_tag(:rock, ui_hint: 'a user hint')
|
|
583
|
+
# #=> <input ... title="a user hint" type="radio" value="1">
|
|
584
|
+
#
|
|
585
|
+
# Supports the <tt>:disabled</tt> & <tt>:checked</tt> attributes.
|
|
586
|
+
#
|
|
587
|
+
# radio_button_tag(:yes, checked: true)
|
|
588
|
+
# #=> <input checked="checked" class="checkbox" id="yes_1"...value="1">
|
|
589
|
+
#
|
|
590
|
+
# radio_button_tag(:yes, disabled: true)
|
|
591
|
+
# #=> <input disabled="disabled" class="checkbox" id="yes_1" ... value="1">
|
|
592
|
+
#
|
|
593
|
+
#
|
|
594
|
+
def radio_button_tag(name, attrs = {})
|
|
595
|
+
attrs.reverse_merge!(name: name, type: :radio, checked: false, value: 1)
|
|
596
|
+
attrs = add_css_id(attrs, name)
|
|
597
|
+
# id_value = [field.to_s,'_',value].join
|
|
598
|
+
attrs[:id] = [attrs[:id], html_safe_id(attrs[:value])].compact.join('_')
|
|
599
|
+
attrs = add_css_class(attrs, :radio)
|
|
600
|
+
attrs = add_ui_hint(attrs)
|
|
601
|
+
tag(:input, attrs)
|
|
602
|
+
end
|
|
603
|
+
alias_method :radiobutton_tag, :radio_button_tag
|
|
604
|
+
|
|
605
|
+
# Creates a submit button with the text value as the caption.
|
|
606
|
+
#
|
|
607
|
+
# ==== Examples
|
|
608
|
+
#
|
|
609
|
+
# <%= submit_tag %> || <%= submit_button %>
|
|
610
|
+
# => <input name="submit" type="submit" value="Save Form">
|
|
611
|
+
#
|
|
612
|
+
# <%= submit_tag(nil) %>
|
|
613
|
+
# => <input name="submit" type="submit" value="">
|
|
614
|
+
#
|
|
615
|
+
# <%= submit_tag("Custom Value") %>
|
|
616
|
+
# => <input name="submit" type="submit" value="Custom Value">
|
|
617
|
+
#
|
|
618
|
+
# Adding a CSS class. NB! input[:submit] has no other class by default.
|
|
619
|
+
#
|
|
620
|
+
# <%= submit_tag(class: 'some-class') %>
|
|
621
|
+
# #=> <input class="some-class" name="submit" type="submit" value="Save Form">
|
|
622
|
+
#
|
|
623
|
+
# Supports the <tt>:disabled</tt> attribute.
|
|
624
|
+
#
|
|
625
|
+
# <%= submit_tag(disabled: true) %>
|
|
626
|
+
# #=> <input disabled="disabled" name="submit" type="submit" value="Save Form">
|
|
627
|
+
#
|
|
628
|
+
# Adds a +:title+ attribute when passed +:ui_hint+. Also works with +:title+.
|
|
629
|
+
#
|
|
630
|
+
# <%= submit_tag(ui_hint: 'a user hint') %>
|
|
631
|
+
# #=> <input name="submit" title="a user hint" type="submit" value="Save Form">
|
|
632
|
+
#
|
|
633
|
+
def submit_tag(value = 'Save Form', attrs = {})
|
|
634
|
+
value, attrs = 'Save Form', value if value.is_a?(Hash)
|
|
635
|
+
attrs.reverse_merge!(type: :submit, name: :submit, value: value)
|
|
636
|
+
attrs = add_ui_hint(attrs)
|
|
637
|
+
self_closing_tag(:input, attrs)
|
|
638
|
+
end
|
|
639
|
+
alias_method :submit_button, :submit_tag
|
|
640
|
+
|
|
641
|
+
# Displays an image which when clicked will submit the form.
|
|
642
|
+
#
|
|
643
|
+
# ==== Examples
|
|
644
|
+
#
|
|
645
|
+
# @img = '/img/btn.png'
|
|
646
|
+
#
|
|
647
|
+
# image_submit_tag(@img)
|
|
648
|
+
# #=> <input src="/img/btn.png" type="image">
|
|
649
|
+
#
|
|
650
|
+
# image_submit_tag(@img, disabled: true)
|
|
651
|
+
# #=> <input disabled="disabled" src="/img/btn.png" type="image">
|
|
652
|
+
#
|
|
653
|
+
# image_submit_tag(@img, class 'search-button')
|
|
654
|
+
# #=> <input class="search-button" src="/img/btn.png" type="image">
|
|
655
|
+
#
|
|
656
|
+
def image_submit_tag(src, attrs = {})
|
|
657
|
+
tag(:input, { type: :image, src: src }.merge(attrs))
|
|
658
|
+
end
|
|
659
|
+
alias_method :imagesubmit_tag, :image_submit_tag
|
|
660
|
+
|
|
661
|
+
# Creates a reset button with the text value as the caption.
|
|
662
|
+
#
|
|
663
|
+
# ==== Examples
|
|
664
|
+
#
|
|
665
|
+
# <%= reset_tag %>
|
|
666
|
+
# => <input name="reset" type="reset" value="Reset Form">
|
|
667
|
+
#
|
|
668
|
+
# <%= reset_tag(nil) %>
|
|
669
|
+
# => <input name="reset" type="reset" value="">
|
|
670
|
+
#
|
|
671
|
+
# Adding a CSS class. NB! input[:reset] has no other class by default.
|
|
672
|
+
#
|
|
673
|
+
# <%= reset_tag('Custom Value', class: 'some-class') %>
|
|
674
|
+
# => <input class="some-class" name="reset" type="reset" value="Custom Value" >
|
|
675
|
+
#
|
|
676
|
+
# Supports the <tt>:disabled</tt> attribute.
|
|
677
|
+
#
|
|
678
|
+
# <%= reset_tag('Custom Value', disabled: true) %>
|
|
679
|
+
# => <input disabled="disabled" name="reset" type="reset" value="Custom Value">
|
|
680
|
+
#
|
|
681
|
+
# Adds a <tt>:title</tt> attribute when passed <tt>:ui_hint</tt>.
|
|
682
|
+
#
|
|
683
|
+
# <%= reset_tag('Custom Value', ui_hint: 'a user hint') %>
|
|
684
|
+
# => <input name="reset" title="a user hint" type="submit" value="Custom Value">
|
|
685
|
+
#
|
|
686
|
+
def reset_tag(value = 'Reset Form', attrs = {})
|
|
687
|
+
value, attrs = 'Reset Form', value if value.is_a?(Hash)
|
|
688
|
+
attrs.reverse_merge!(type: :reset, name: :reset, value: value)
|
|
689
|
+
attrs = add_ui_hint(attrs)
|
|
690
|
+
self_closing_tag(:input, attrs)
|
|
691
|
+
end
|
|
692
|
+
alias_method :reset_button, :reset_tag
|
|
693
|
+
|
|
694
|
+
# Creates a dropdown selection menu.
|
|
695
|
+
#
|
|
696
|
+
# If the :multiple option is set to true, a multiple choice selection box
|
|
697
|
+
# is created.
|
|
698
|
+
#
|
|
699
|
+
# ==== Attributes
|
|
700
|
+
#
|
|
701
|
+
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
|
|
702
|
+
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
|
703
|
+
#
|
|
704
|
+
# Any other key creates standard HTML attributes for the tag.
|
|
705
|
+
#
|
|
706
|
+
#
|
|
707
|
+
# ==== Examples
|
|
708
|
+
#
|
|
709
|
+
# NB! the format for the options values must be [value, key].
|
|
710
|
+
#
|
|
711
|
+
# With Options values as a Hash
|
|
712
|
+
#
|
|
713
|
+
# select_tag(:letters, {a: 'A', b: 'B' })
|
|
714
|
+
# #=>
|
|
715
|
+
# <select id="letters" name="letters">
|
|
716
|
+
# <option value="a">A</option>
|
|
717
|
+
# <option value="b">B</option>
|
|
718
|
+
# </select>
|
|
719
|
+
#
|
|
720
|
+
# With Options values as an Array
|
|
721
|
+
#
|
|
722
|
+
# @letters = [[:a,'A'], [:b,'B']]
|
|
723
|
+
#
|
|
724
|
+
# select_tag(:letters, @letters)
|
|
725
|
+
# #=>
|
|
726
|
+
# <select id="letters" name="letters">
|
|
727
|
+
# <option value="a">A</option>
|
|
728
|
+
# <option value="b">B</option>
|
|
729
|
+
# </select>
|
|
730
|
+
#
|
|
731
|
+
#
|
|
732
|
+
# With Options values as an Array
|
|
733
|
+
#
|
|
734
|
+
# select_tag(:letters, @letters, selected: :a)
|
|
735
|
+
# #=>
|
|
736
|
+
# <select id="letters" name="letters">
|
|
737
|
+
# <option selected="selected" value="a">A</option>
|
|
738
|
+
# <snip...>
|
|
739
|
+
#
|
|
740
|
+
# When passing multiple items to :selected, the select menu automatically becomes
|
|
741
|
+
# a multiple select box. <b>NB! the [] on the <tt>:name</tt> attribute</b>
|
|
742
|
+
#
|
|
743
|
+
# select_tag(:letters, @letters, selected: [:a,'b'])
|
|
744
|
+
# #=>
|
|
745
|
+
# <select id="letters" multiple="multiple" name="letters[]">
|
|
746
|
+
# <option selected="selected" value="a">A</option>
|
|
747
|
+
# <option selected="selected" value="b">B</option>
|
|
748
|
+
# </select>
|
|
749
|
+
#
|
|
750
|
+
# When { multiple: true }, the select menu becomes a select box allowing multiple choices.
|
|
751
|
+
# <b>NB! the [] on the <tt>:name</tt> attribute</b>
|
|
752
|
+
#
|
|
753
|
+
# select_tag(:letters, @letters, multiple: true)
|
|
754
|
+
# #=>
|
|
755
|
+
# <select id="letters" name="letters[]" multiple="multiple">
|
|
756
|
+
# <snip...>
|
|
757
|
+
#
|
|
758
|
+
# select_tag(:letters, @letters, disabled: true)
|
|
759
|
+
# #=>
|
|
760
|
+
# <select id="letters" disabled="disabled" name="letters">
|
|
761
|
+
# <snip...>
|
|
762
|
+
#
|
|
763
|
+
# select_tag(:letters, @letters, id: 'my-letters')
|
|
764
|
+
# #=>
|
|
765
|
+
# <select id="my-letters" name="letters">
|
|
766
|
+
# <snip...>
|
|
767
|
+
#
|
|
768
|
+
# select_tag(:letters, @letters, class: 'funky-select')
|
|
769
|
+
# #=>
|
|
770
|
+
# <select class="funky-select" id="my-letters" name="letters">
|
|
771
|
+
# <snip...>
|
|
772
|
+
#
|
|
773
|
+
# select_tag(:letters, @letters, prompt: true)
|
|
774
|
+
# #=>
|
|
775
|
+
# <select id="letters" name="letters">
|
|
776
|
+
# <option selected="selected" value="">- Select -</option>
|
|
777
|
+
# <snip...>
|
|
778
|
+
#
|
|
779
|
+
# select_tag(:letters, @letters, prompt: 'Top Letters', selected: 'a')
|
|
780
|
+
# #=>
|
|
781
|
+
# <select id="letters" name="letters">
|
|
782
|
+
# <option value="">Top Letters</option>
|
|
783
|
+
# <option selected="selected" value="a">A</option>
|
|
784
|
+
# <snip...>
|
|
785
|
+
#
|
|
786
|
+
#
|
|
787
|
+
def select_tag(name, options, attrs = {})
|
|
788
|
+
options = options.to_a.reverse if options.is_a?(Hash)
|
|
789
|
+
attrs[:multiple] = true if attrs[:selected].is_a?(Array)
|
|
790
|
+
options_html = select_options(options, attrs)
|
|
791
|
+
attrs.delete(:selected)
|
|
792
|
+
# attrs = add_css_id(attrs, name)
|
|
793
|
+
add_css_id(attrs, name)
|
|
794
|
+
html_name = (attrs[:multiple] == true && !name.to_s.end_with?('[]')) ? "#{name}[]" : name
|
|
795
|
+
tag(:select, options_html, { name: html_name }.merge(attrs))
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
# Return select option _contents_ with _value_.
|
|
799
|
+
#
|
|
800
|
+
# ==== Examples
|
|
801
|
+
#
|
|
802
|
+
# select_option('a', 'Letter A') #=> <option value="a">Letter A</option>
|
|
803
|
+
#
|
|
804
|
+
# select_option('on', '') #=> <option value="on">On</option>
|
|
805
|
+
#
|
|
806
|
+
# select_option('a', 'Letter A', selected: true)
|
|
807
|
+
# #=> <option selected="selected" value="a">Letter A</option>
|
|
808
|
+
#
|
|
809
|
+
# select_option('a', 'Letter A', selected: false)
|
|
810
|
+
# #=> <option value="a">Letter A</option>
|
|
811
|
+
#
|
|
812
|
+
def select_option(value, key, attrs = {})
|
|
813
|
+
key = value.to_s.titleize if key.blank?
|
|
814
|
+
tag(:option, key, { value: value }.merge(attrs))
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
# Support Rack::MethodOverride
|
|
818
|
+
#
|
|
819
|
+
def faux_method(method = 'PUT')
|
|
820
|
+
hidden_field_tag(:input, name: '_method', value: method.to_s.upcase)
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
private
|
|
825
|
+
|
|
826
|
+
#
|
|
827
|
+
def opts_tag_helpers
|
|
828
|
+
opts[:tag_helpers]
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
#
|
|
832
|
+
def html_safe_id(id)
|
|
833
|
+
id.to_s.downcase.gsub(/\W/, '-').gsub('--', '-')
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
# do we have a class attrs already
|
|
837
|
+
def add_css_class(attrs, new_class = nil)
|
|
838
|
+
merge_attr_classes(attrs, new_class)
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
#
|
|
842
|
+
def add_css_id(attrs, new_id)
|
|
843
|
+
attrs = {} if attrs.nil?
|
|
844
|
+
new_id = '' if new_id.is_a?(Hash)
|
|
845
|
+
id_value = attrs[:id].nil? ? html_safe_id(new_id.to_s) : attrs.delete(:id)
|
|
846
|
+
attrs[:id] = id_value.to_s unless id_value == false
|
|
847
|
+
attrs[:id] = nil if attrs[:id] == '' # set to nil to remove from tag output
|
|
848
|
+
attrs
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
#
|
|
852
|
+
def add_ui_hint(attrs)
|
|
853
|
+
attrs[:title] = attrs.delete(:ui_hint) unless attrs[:ui_hint].nil?
|
|
854
|
+
attrs
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
# Return select option elements from _values_ with _options_ passed.
|
|
858
|
+
#
|
|
859
|
+
# === Options
|
|
860
|
+
#
|
|
861
|
+
# :selected string, symbol, or array of options selected
|
|
862
|
+
#
|
|
863
|
+
# ==== Examples
|
|
864
|
+
#
|
|
865
|
+
#
|
|
866
|
+
def select_options(values, attrs = {})
|
|
867
|
+
attrs = {} if attrs.blank?
|
|
868
|
+
values = [] if values.blank?
|
|
869
|
+
normalize_select_prompt(values, attrs)
|
|
870
|
+
# { :a => 'A' }
|
|
871
|
+
# [5, 'E']
|
|
872
|
+
# FIXME:: when passed a Hash of values, they become reversed (last first and so on..)
|
|
873
|
+
|
|
874
|
+
values.map do |value, key|
|
|
875
|
+
if value.is_a?(Hash)
|
|
876
|
+
tag(:optgroup, select_options(value, attrs), label: key)
|
|
877
|
+
elsif option_selected?(value, attrs[:selected])
|
|
878
|
+
select_option(value, key, selected: true)
|
|
879
|
+
else
|
|
880
|
+
select_option(value, key)
|
|
881
|
+
end
|
|
882
|
+
end.join
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
# Normalize select prompt.
|
|
886
|
+
#
|
|
887
|
+
# * When +attrs+ contains a :prompt string it is assigned as the prompt
|
|
888
|
+
# * When :prompt is true the default of '- Select Model -' will become the prompt
|
|
889
|
+
# * The prompt is selected unless a specific option is explicitly selected.
|
|
890
|
+
#
|
|
891
|
+
def normalize_select_prompt(values, attrs = {})
|
|
892
|
+
return unless attrs.key?(:prompt)
|
|
893
|
+
prompt = attrs.delete(:prompt)
|
|
894
|
+
attrs[:selected] = '' unless attrs.include?(:selected)
|
|
895
|
+
prompt_text = prompt == true ? '- Select -' : prompt
|
|
896
|
+
values.unshift(['', prompt_text])
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
# Check if option _key_ is _selected_.
|
|
900
|
+
def option_selected?(key, selection)
|
|
901
|
+
# if Array === selection
|
|
902
|
+
if selection.is_a?(Array)
|
|
903
|
+
# (selection.map { |s| s.to_s }).include?(key.to_s)
|
|
904
|
+
(selection.map(&:to_s)).include?(key.to_s)
|
|
905
|
+
else
|
|
906
|
+
selection.to_s == key.to_s
|
|
907
|
+
end
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
end # /InstanceMethods
|
|
912
|
+
|
|
913
|
+
end # /RodaTagHelpers
|
|
914
|
+
|
|
915
|
+
register_plugin(:tag_helpers, RodaTagHelpers)
|
|
916
|
+
|
|
917
|
+
end # /RodaPlugins
|
|
918
|
+
|
|
919
|
+
end
|