express_templates 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -5
- data/lib/express_templates/components.rb +2 -0
- data/lib/express_templates/components/capabilities/parenting.rb +1 -1
- data/lib/express_templates/components/capabilities/wrapping.rb +1 -1
- data/lib/express_templates/components/content_for.rb +5 -1
- data/lib/express_templates/components/for_each.rb +1 -1
- data/lib/express_templates/components/form_for.rb +375 -8
- data/lib/express_templates/components/table_for.rb +54 -10
- data/lib/express_templates/components/tree_for.rb +46 -5
- data/lib/express_templates/expander.rb +1 -5
- data/lib/express_templates/macro.rb +1 -0
- data/lib/express_templates/version.rb +1 -1
- data/test/components/container_test.rb +16 -1
- data/test/components/form_for_test.rb +197 -0
- data/test/components/table_for_test.rb +128 -33
- data/test/components/tree_for_test.rb +103 -0
- data/test/dummy/app/views/hello/show.html.et +1 -1
- data/test/dummy/config/environments/production.rb +1 -1
- data/test/dummy/config/environments/test.rb +2 -1
- data/test/dummy/log/test.log +558 -146934
- data/test/dummy/test/controllers/hello_controller_test.rb +1 -1
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/test_helper.rb +2 -0
- metadata +13 -9
- data/test/dummy/log/development.log +0 -6478
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 833fc8181d87deb3b99763fb91dfdad3b48c6c9e
|
4
|
+
data.tar.gz: cb4037d2a9bcd7c2e3084ea9ec2026693f71da5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2040b7bf2a3fb485bd6d454532c41b3467700efaac36f50333fcd9d8c16d0055f77bd3888640f11f9dc972540504697cf9e92818aaab8ba19c24ecbcc9cd71b
|
7
|
+
data.tar.gz: 79e23baf7ea8315fbd06f85b6433b658c233847973de3ddc07d20ddc7cb086c183aee8858bc856e1d24a7c3dd9e2ad234a6151715c096245b8223217f76994aa
|
data/README.md
CHANGED
@@ -58,11 +58,11 @@ ExpressTemplates introduces an earlier step in this process, "expansion", which
|
|
58
58
|
|
59
59
|
## Constraints - Important!
|
60
60
|
|
61
|
-
ExpressTemplates imposes some constraints. The most important constraint is that your view templates must be
|
61
|
+
ExpressTemplates imposes some constraints. The most important constraint is that your view templates must be declarative in style. They should not contain conditional logic. Declarative code is easier to read and reason about. It also requires fewer tests since declarative code is build on presumably well-tested primitives.
|
62
62
|
|
63
|
-
With ExpressTemplates, one *must not*
|
63
|
+
With ExpressTemplates, one *must not* place conditional logic or iterators anywhere in template code. All logic *must* be encapsulated in components. Strange things will happen if you try to put logic in the template or a template fragment. In the future I may issue warnings or disallow it by examinging the output of Ruby's tokenizer.
|
64
64
|
|
65
|
-
If you have been around long enough to see a few Rails codebases grow out of control, and you have had to manage or watch the efforts of less-experienced developers closely, you know that one of the major causes of trouble and wasted effort is copy-and-paste code and logic errors in the view. Another common problem is the "blank slate" issue wherein every view must be constructed new with little chance for
|
65
|
+
If you have been around long enough to see a few Rails codebases grow out of control, and you have had to manage or watch the efforts of less-experienced developers closely, you know that one of the major causes of trouble and wasted effort is copy-and-paste code and logic errors in the view. Another common problem is the "blank slate" issue wherein every view must be constructed new with little chance for higher-level reuse of code. Diligent use of partials and helpers can do much to DRY up view code but deciding where to put them or how to share them between projects can be difficult. Rarely is view logic tested except in integration.
|
66
66
|
|
67
67
|
ExpressTemplates only enforces what is already considered a best practice by many, while introducing new possilibities for well-ordered UX libraries similar to what developers working with commercial frameworks for desktop operating systems or mobile devices enjoy.
|
68
68
|
|
@@ -82,7 +82,13 @@ ul {
|
|
82
82
|
|
83
83
|
Let us suppose that an @three variable exists in the view context with the value "three". This would yield the following markup:
|
84
84
|
|
85
|
-
|
85
|
+
```html
|
86
|
+
<ul>
|
87
|
+
<li>one</li>
|
88
|
+
<li>two</li>
|
89
|
+
<li>three</li>
|
90
|
+
</ul>
|
91
|
+
```
|
86
92
|
|
87
93
|
yield and local variables which we may expect to be available in a ViewContext are also wrapped for evaluation later.
|
88
94
|
|
@@ -129,7 +135,15 @@ div.active {
|
|
129
135
|
|
130
136
|
Now when the template renders, it will yield:
|
131
137
|
|
132
|
-
|
138
|
+
```html
|
139
|
+
<div class="active">
|
140
|
+
<ul>
|
141
|
+
<li>one</li>
|
142
|
+
<li>two</li>
|
143
|
+
<li>three</li>
|
144
|
+
</ul>
|
145
|
+
</div>
|
146
|
+
```
|
133
147
|
|
134
148
|
## Background
|
135
149
|
|
@@ -12,5 +12,7 @@ require 'express_templates/components/unless_block'
|
|
12
12
|
require 'express_templates/components/row'
|
13
13
|
require 'express_templates/components/column'
|
14
14
|
require 'express_templates/components/form_rails_support'
|
15
|
+
require 'express_templates/components/form_for'
|
15
16
|
require 'express_templates/components/content_for'
|
16
17
|
require 'express_templates/components/table_for'
|
18
|
+
require 'express_templates/components/tree_for'
|
@@ -45,7 +45,7 @@ module ExpressTemplates
|
|
45
45
|
|
46
46
|
def compile
|
47
47
|
null_wrapped_children = "null_wrap { #{compile_children} }"
|
48
|
-
wrap_children_src = self.class[:markup].source.gsub(
|
48
|
+
wrap_children_src = self.class[:markup].source.gsub(/(\s)_yield(\s)/, '\1'+null_wrapped_children+'\2')
|
49
49
|
_compile_fragment(Proc.from_source(wrap_children_src))
|
50
50
|
end
|
51
51
|
|
@@ -10,6 +10,10 @@ module ExpressTemplates
|
|
10
10
|
# h1 "Title"
|
11
11
|
# }
|
12
12
|
# ```
|
13
|
+
# Or:
|
14
|
+
# ```ruby
|
15
|
+
# content_for(:page_title), "People"
|
16
|
+
# ```
|
13
17
|
class ContentFor < Container
|
14
18
|
include Capabilities::Configurable
|
15
19
|
def compile
|
@@ -35,4 +39,4 @@ module ExpressTemplates
|
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
38
|
-
end
|
42
|
+
end
|
@@ -5,15 +5,382 @@ module ExpressTemplates
|
|
5
5
|
#
|
6
6
|
# Example:
|
7
7
|
#
|
8
|
-
#
|
9
|
-
# form_for(:people) do |
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
8
|
+
# ````ruby
|
9
|
+
# form_for(:people) do |f|
|
10
|
+
# f.text_field :name
|
11
|
+
# f.email_field :email
|
12
|
+
# f.phone_field :phone, wrapper_class: 'field phone'
|
13
|
+
# f.submit 'Save'
|
13
14
|
# end
|
14
|
-
#
|
15
|
+
# ````
|
15
16
|
#
|
16
|
-
|
17
|
+
# This assumes that @people variable will exist in the
|
18
|
+
# view and that it will be a collection whose members respond to :name, :email etc.
|
19
|
+
#
|
20
|
+
# This will result in markup like the following:
|
21
|
+
#
|
22
|
+
# ````
|
23
|
+
# <form action="/people" method="post">
|
24
|
+
# <div style="display:none">
|
25
|
+
# <input name="utf8" type="hidden" value="✓">
|
26
|
+
# <input type="hidden" name="_method" value="post">
|
27
|
+
# <input type="hidden" name="authenticity_token" value="5ZDztTe1N4tc03QSjmMdSVqAw==">
|
28
|
+
# </div>
|
29
|
+
#
|
30
|
+
# <div>
|
31
|
+
# <label for="person_name">Name</label>
|
32
|
+
# <input type="text" name="person[name]" id="person_name" />
|
33
|
+
# </div>
|
34
|
+
#
|
35
|
+
# <div>
|
36
|
+
# <label for="person_email">Email</label>
|
37
|
+
# <input type="email" name="person[email]" id="person_email" />
|
38
|
+
# </div>
|
39
|
+
#
|
40
|
+
# <div class="field phone">
|
41
|
+
# <label for="person_phone">Phone</label>
|
42
|
+
# <input type="tel" name="person[phone]" id="person_phone" />
|
43
|
+
# </div>
|
44
|
+
#
|
45
|
+
# <div>
|
46
|
+
# <input type="submit" name="commit" value="Save" />
|
47
|
+
# </div>
|
48
|
+
# </form>
|
49
|
+
# ````
|
50
|
+
#
|
51
|
+
# As seen above, each field is accompanied by a label and is wrapped by a div.
|
52
|
+
# The div can be further styled by adding css classes to it via the `wrapper_class` option.
|
53
|
+
#
|
54
|
+
# Example:
|
55
|
+
#
|
56
|
+
# ````ruby
|
57
|
+
# form_for(:posts) do
|
58
|
+
# f.text_field :title, wrapped_class: 'string optional'
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# Will result to generating HTML like so:
|
62
|
+
#
|
63
|
+
# ````
|
64
|
+
# ...
|
65
|
+
# <div class='string optional'>
|
66
|
+
# <label for='post_title'>Title</label>
|
67
|
+
# <input type="text" name="post[title]" id="post_title" />
|
68
|
+
# </div>
|
69
|
+
# ...
|
70
|
+
# ````
|
71
|
+
#
|
72
|
+
# In addition to this, label text can also be customized using the `label` option:
|
73
|
+
#
|
74
|
+
# ````ruby
|
75
|
+
# f.email_field :email_address, label: 'Your Email'
|
76
|
+
# ````
|
77
|
+
#
|
78
|
+
# Compiles to;
|
79
|
+
# ````
|
80
|
+
# <label for='user_email'>Your Email</label>
|
81
|
+
# <input type='email' name='user[email]' id='user_email' />
|
82
|
+
# ````
|
83
|
+
class FormFor < Base
|
84
|
+
include Capabilities::Configurable
|
85
|
+
include Capabilities::Building
|
86
|
+
|
87
|
+
def initialize(*args)
|
88
|
+
# TODO: need a better way to select the form options
|
89
|
+
@form_options = args.select { |x| x.is_a?(Hash) }
|
90
|
+
super(*args)
|
91
|
+
_process_args!(args) # from Configurable
|
92
|
+
yield(self) if block_given?
|
93
|
+
end
|
94
|
+
|
95
|
+
attr :fields
|
96
|
+
|
97
|
+
# Express Templates uses Rails' form helpers to generate the fields with labels
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
#
|
101
|
+
# ````ruby
|
102
|
+
# form_for(:people) do |f|
|
103
|
+
# f.phone_field :phone
|
104
|
+
# end
|
105
|
+
# ````
|
106
|
+
#
|
107
|
+
# This will precompile as
|
108
|
+
#
|
109
|
+
# ````ruby
|
110
|
+
# ...
|
111
|
+
# phone_field_tag :phone, @people.phone, {}
|
112
|
+
# ...
|
113
|
+
# ````
|
114
|
+
#
|
115
|
+
# Fields can also have custom classes via the `class` option:
|
116
|
+
#
|
117
|
+
# Example:
|
118
|
+
#
|
119
|
+
# ````ruby
|
120
|
+
# f.url_field :website_url, class: 'url-string'
|
121
|
+
# ````
|
122
|
+
#
|
123
|
+
# Compiles to:
|
124
|
+
#
|
125
|
+
# ````
|
126
|
+
# <input type='url' name='post[website_url]' id='post_website_url' class='url-string' />
|
127
|
+
# ````
|
128
|
+
#
|
129
|
+
# You can also add in the basic options supported by the
|
130
|
+
# phone_field_tag [here](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-phone_field_tag)
|
131
|
+
#
|
132
|
+
# This applies to all the other '_field_tags' listed
|
133
|
+
# [here](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html)
|
134
|
+
#
|
135
|
+
#
|
136
|
+
# = Fields
|
137
|
+
# ````ruby
|
138
|
+
# f.text_field :name
|
139
|
+
# # <div>
|
140
|
+
# # <label for="person_name">Name</label>
|
141
|
+
# # <input type="text" name="person[name]" id="person_name" />
|
142
|
+
# # </div>
|
143
|
+
#
|
144
|
+
# f.text_field :name, label: 'post title'
|
145
|
+
# # <div>
|
146
|
+
# # <label for="person_name">Post Title</label>
|
147
|
+
# # <input type="text" name="person[name]" id="person_name" />
|
148
|
+
# # </div>
|
149
|
+
#
|
150
|
+
# f.text_field :name, class: 'string'
|
151
|
+
# # <div>
|
152
|
+
# # <label for="person_name">Name</label>
|
153
|
+
# # <input type="text" name="person[name]" class='string' id="person_name" />
|
154
|
+
# # </div>
|
155
|
+
#
|
156
|
+
# f.text_field :name, wrapper_class: 'field input'
|
157
|
+
# # <div class="field input">
|
158
|
+
# # <label for="person_name">Name</label>
|
159
|
+
# # <input type="text" name="person[name]" id="person_name" />
|
160
|
+
# # </div>
|
161
|
+
#
|
162
|
+
# ````
|
163
|
+
%w(email phone text password color date datetime
|
164
|
+
datetime_local hidden number range
|
165
|
+
search telephone time url week).each do |type|
|
166
|
+
define_method("#{type}_field") do |name, options={}|
|
167
|
+
@fields ||= []
|
168
|
+
@fields << Field.new(name, options, type.to_sym)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# ==== Examples
|
173
|
+
# f.select :gender, ['Male', 'Female'], selected: 'Male'
|
174
|
+
# # <div>
|
175
|
+
# # <label for="person_gender">Gender</label>
|
176
|
+
# # <select id="person_gender" name="person[gender]">
|
177
|
+
# # <option selected="selected" value="Male">Male</option>
|
178
|
+
# # <option selected="selected" value="Female">Female</option>
|
179
|
+
# # </select>
|
180
|
+
# # </div>
|
181
|
+
# f.select :name, options_from_collection_for_select(@people, "id", "name")
|
182
|
+
# # <div>
|
183
|
+
# # <label for="person_name">Name</label>
|
184
|
+
# # <select id="people_name" name="people[name]"><option value="1">David</option></select>
|
185
|
+
# # </div>
|
186
|
+
#
|
187
|
+
def select(name, select_options, options = {})
|
188
|
+
@fields ||= []
|
189
|
+
@fields << Select.new(name, options.merge!(select_options: select_options))
|
190
|
+
end
|
191
|
+
|
192
|
+
# ==== Examples
|
193
|
+
# f.radio :card, [[1, 'One'], [2, 'Two']], :first, :last
|
194
|
+
# # <div>
|
195
|
+
# # <label class="radio" for="user_age_1"><input type="radio" value="1" name="user[age]" id="user_age_1">One</label>
|
196
|
+
# # <label class="radio" for="user_age_2"><input type="radio" value="2" name="user[age]" id="user_age_2">Two</label>
|
197
|
+
# # </div>
|
198
|
+
#
|
199
|
+
def radio(name, collection, value_method, text_method, options = {})
|
200
|
+
@fields ||= []
|
201
|
+
@fields << Radio.new(name, options.merge!(collection: collection, value_method: value_method, text_method: text_method))
|
202
|
+
end
|
203
|
+
|
204
|
+
# ==== Examples
|
205
|
+
# f.checkbox :age, [[1, 'One'], [2, 'Two']], :first, :last
|
206
|
+
# # <div>
|
207
|
+
# # <label class="checkbox" for="user_age_1">
|
208
|
+
# # <input type="checkbox" value="1" name="user[age][]" id="user_age_1">
|
209
|
+
# # "One"
|
210
|
+
# # </label>
|
211
|
+
# # <label>
|
212
|
+
# # <input type="checkbox" value="2" name="user[age][]" id="user_age_2">
|
213
|
+
# # "Two"
|
214
|
+
# # </label>
|
215
|
+
# # </div>
|
216
|
+
#
|
217
|
+
def checkbox(name, collection, value_method, text_method, options = {})
|
218
|
+
@fields ||= []
|
219
|
+
@fields << Checkbox.new(name, options.merge!(collection: collection, value_method: value_method, text_method: text_method))
|
220
|
+
end
|
221
|
+
|
222
|
+
# ==== Examples
|
223
|
+
# f.text_area :name
|
224
|
+
# # <div>
|
225
|
+
# # <label for="user_name">Name</label>
|
226
|
+
# # <textarea name="user[name]" id="user_name" >
|
227
|
+
# # </div>
|
228
|
+
# f.text_area :name, label: 'post title'
|
229
|
+
# # <div>
|
230
|
+
# # <label for="user_name">Post Title</label>
|
231
|
+
# # <textarea name="user[name]" id="user_name" >
|
232
|
+
# # </div>
|
233
|
+
# f.text_area :name, wrapper_class: 'field input'
|
234
|
+
# # <div class="field input">
|
235
|
+
# # <label for="user_name">Name</label>
|
236
|
+
# # <textarea name="user[name]" id="user_name" >
|
237
|
+
# # </div>
|
238
|
+
# f.text_area :name, class: 'string'
|
239
|
+
# # <div>
|
240
|
+
# # <label for="user_name>Name</label>
|
241
|
+
# # <textarea name="user[name] id="user_name" class="string" >
|
242
|
+
# # </div>
|
243
|
+
#
|
244
|
+
def text_area(name, options = {})
|
245
|
+
@fields ||= []
|
246
|
+
@fields << TextArea.new(name, options)
|
247
|
+
end
|
248
|
+
|
249
|
+
# ==== Examples
|
250
|
+
# f.submit "Save Changes"
|
251
|
+
# # <div>
|
252
|
+
# # <input type="submit" name="commit" value="Save Changes" />
|
253
|
+
# # </div>
|
254
|
+
#
|
255
|
+
def submit(name = 'Submit Changes', options = {})
|
256
|
+
@fields ||=[]
|
257
|
+
@fields << Field.new(name, options, :submit)
|
258
|
+
end
|
259
|
+
|
260
|
+
emits -> {
|
261
|
+
resource_name = my[:id].to_s
|
262
|
+
form_options = @form_options.first
|
263
|
+
form_method = form_options.delete :method if form_options
|
264
|
+
|
265
|
+
form_method = if form_method == :put
|
266
|
+
:patch
|
267
|
+
else
|
268
|
+
form_options.present? ? form_options[:method] : :post
|
269
|
+
end
|
270
|
+
|
271
|
+
form_action = if form_method == :patch
|
272
|
+
%Q(/#{resource_name.pluralize}/{{@#{resource_name}.id}})
|
273
|
+
else
|
274
|
+
%Q(/#{resource_name.pluralize})
|
275
|
+
end
|
276
|
+
|
277
|
+
form_args = {action: form_action, method: :post}
|
278
|
+
form_args.merge!(form_options) unless form_options.nil?
|
279
|
+
|
280
|
+
form(form_args) {
|
281
|
+
form_rails_support form_method
|
282
|
+
fields.each do |field|
|
283
|
+
field_name = field.name
|
284
|
+
field_type = field.type.to_s
|
285
|
+
resource_field_name = "#{resource_name.singularize}[#{field_name}]"
|
286
|
+
label_name = "#{resource_name.singularize}_#{field_name}"
|
287
|
+
field_label = field.label || field_name.to_s.capitalize
|
288
|
+
|
289
|
+
div(class: field.wrapper_class) {
|
290
|
+
if field_type == 'select'
|
291
|
+
label_tag(label_name, field_label)
|
292
|
+
select_tag(resource_field_name, field.options_html, field.options)
|
293
|
+
elsif field_type == 'radio'
|
294
|
+
collection_radio_buttons(my[:id], field_name, field.collection,
|
295
|
+
field.value_method, field.text_method, field.options) do |b|
|
296
|
+
b.label(class: 'radio') { b.radio_button + b.text }
|
297
|
+
end
|
298
|
+
elsif field_type == 'checkbox'
|
299
|
+
collection_check_boxes(my[:id], field_name, field.collection,
|
300
|
+
field.value_method, field.text_method, field.options) do |b|
|
301
|
+
b.label(class: 'checkbox') { b.check_box + b.text }
|
302
|
+
end
|
303
|
+
elsif field_type == 'submit'
|
304
|
+
submit_tag(field_name, field.options)
|
305
|
+
else
|
306
|
+
label_tag(label_name, field_label) unless field_type == 'hidden'
|
307
|
+
args = [resource_field_name, "{{@#{resource_name.singularize}.#{field_name}}}", field.options]
|
308
|
+
tag_string = if field_type == 'text_area'
|
309
|
+
'text_area_tag'
|
310
|
+
else
|
311
|
+
"#{field_type}_field_tag"
|
312
|
+
end
|
313
|
+
|
314
|
+
self.send(tag_string.to_sym, *args)
|
315
|
+
end
|
316
|
+
}
|
317
|
+
end
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
def wrap_for_stack_trace(body)
|
322
|
+
"ExpressTemplates::Components::FormFor.render_in(self) {\n#{body}\n}"
|
323
|
+
end
|
324
|
+
|
325
|
+
def compile
|
326
|
+
wrap_for_stack_trace(lookup(:markup))
|
327
|
+
end
|
328
|
+
|
329
|
+
class Field
|
330
|
+
attr :name, :options, :label, :type, :wrapper_class
|
331
|
+
def initialize(name, options = {}, type=:text)
|
332
|
+
@name = name
|
333
|
+
@options = options
|
334
|
+
@label = options[:label]
|
335
|
+
@wrapper_class = @options.delete(:wrapper_class)
|
336
|
+
@type = type
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
class TextArea < Field
|
341
|
+
def initialize(name, options={})
|
342
|
+
super(name, options, :text_area)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class Radio < Field
|
347
|
+
attr :collection, :value_method, :text_method
|
348
|
+
def initialize(name, options = {})
|
349
|
+
@collection = options.delete :collection
|
350
|
+
@value_method = options.delete :value_method
|
351
|
+
@text_method = options.delete :text_method
|
352
|
+
super(name, options, :radio)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
class Checkbox < Radio
|
357
|
+
def initialize(name, options = {})
|
358
|
+
super(name, options)
|
359
|
+
@type = :checkbox
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
class Select < Field
|
364
|
+
attr :choices
|
365
|
+
def initialize(name, options = {})
|
366
|
+
@choices = options.delete :select_options
|
367
|
+
@selected = options.delete :selected
|
368
|
+
super(name, options, :select)
|
369
|
+
end
|
370
|
+
|
371
|
+
def options_html
|
372
|
+
choice_string = ""
|
373
|
+
if @choices.is_a?(String)
|
374
|
+
choice_string = @choices
|
375
|
+
else
|
376
|
+
@choices.map do |choice|
|
377
|
+
selected_string = (@selected != nil && choice == @selected) ? 'selected=selected' : nil
|
378
|
+
choice_string << "<option #{selected_string}>#{choice}</option>"
|
379
|
+
end
|
380
|
+
"{{'#{choice_string}'.html_safe}}"
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
17
384
|
end
|
18
385
|
end
|
19
|
-
end
|
386
|
+
end
|