manatee 0.0.1.pre1
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/Gemfile +23 -0
- data/LICENSE.txt +22 -0
- data/README.mdown +55 -0
- data/Rakefile +7 -0
- data/app/assets/javascripts/manatee.js +1 -0
- data/app/assets/javascripts/manatee/helpers.js +4 -0
- data/app/assets/javascripts/manatee/helpers/asset_tag.jsh.coffee +138 -0
- data/app/assets/javascripts/manatee/helpers/asset_url.jsh.coffee +90 -0
- data/app/assets/javascripts/manatee/helpers/csrf.jsh.coffee +5 -0
- data/app/assets/javascripts/manatee/helpers/date.jsh.coffee +54 -0
- data/app/assets/javascripts/manatee/helpers/debug.jsh.coffee +2 -0
- data/app/assets/javascripts/manatee/helpers/form.jsh.coffee +25 -0
- data/app/assets/javascripts/manatee/helpers/form_builder.jsh.coffee +24 -0
- data/app/assets/javascripts/manatee/helpers/form_options.jsh.coffee +267 -0
- data/app/assets/javascripts/manatee/helpers/form_tag.jsh.coffee +204 -0
- data/app/assets/javascripts/manatee/helpers/javascript.jsh.coffee +15 -0
- data/app/assets/javascripts/manatee/helpers/number.jsh.coffee +58 -0
- data/app/assets/javascripts/manatee/helpers/sanitize.jsh.coffee +5 -0
- data/app/assets/javascripts/manatee/helpers/tag.jsh.coffee +58 -0
- data/app/assets/javascripts/manatee/helpers/text.jsh.coffee +12 -0
- data/app/assets/javascripts/manatee/helpers/translation.jsh.coffee +7 -0
- data/app/assets/javascripts/manatee/helpers/url.jsh.coffee +36 -0
- data/app/assets/javascripts/manatee/helpers/util.jsh.coffee +41 -0
- data/app/assets/javascripts/manatee/rails_helpers.js +2 -0
- data/app/assets/javascripts/manatee/rails_helpers/routes.js.erb +195 -0
- data/app/assets/javascripts/manatee/rails_routes.js +1 -0
- data/app/assets/javascripts/manatee/renderer.js.erb +53 -0
- data/app/assets/javascripts/manatee_railsless.js +1 -0
- data/lib/manatee.rb +87 -0
- data/lib/manatee/config.rb +51 -0
- data/lib/manatee/handler.rb +45 -0
- data/lib/manatee/rails.rb +6 -0
- data/lib/manatee/rails/extensions.rb +23 -0
- data/lib/manatee/rails/handler.rb +16 -0
- data/lib/manatee/rails/hash_visitor.rb +35 -0
- data/lib/manatee/rails/helper.rb +9 -0
- data/lib/manatee/rails/resolver.rb +70 -0
- data/lib/manatee/rails/routes_compiler.rb +34 -0
- data/lib/manatee/sprockets.rb +8 -0
- data/lib/manatee/sprockets/jsh_processor_2x.rb +32 -0
- data/lib/manatee/sprockets/jsh_processor_3x.rb +31 -0
- data/lib/manatee/version.rb +3 -0
- data/manatee.gemspec +32 -0
- data/test/example/renderer.js.erb +8 -0
- data/test/example/translations.en.yml +410 -0
- data/test/example/views/index.jst.eco +12 -0
- data/test/helpers/asset_tag_test.rb +175 -0
- data/test/helpers/asset_url_test.rb +349 -0
- data/test/helpers/form_options_test.rb +718 -0
- data/test/helpers/form_tag_test.rb +387 -0
- data/test/helpers/javascript_test.rb +39 -0
- data/test/helpers/number_test.rb +111 -0
- data/test/helpers/tag_test.rb +71 -0
- data/test/support/dom_assertion.rb +49 -0
- data/test/support/view_test.rb +91 -0
- data/test/test_helper.rb +17 -0
- metadata +213 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
# _to_partial_path
|
3
|
+
# button
|
4
|
+
# check_box
|
5
|
+
# collection_check_boxes
|
6
|
+
# collection_radio_buttons
|
7
|
+
# collection_select
|
8
|
+
# date_select
|
9
|
+
# datetime_select
|
10
|
+
# emitted_hidden_id?
|
11
|
+
# fields_for
|
12
|
+
# file_field
|
13
|
+
# grouped_collection_select
|
14
|
+
# hidden_field
|
15
|
+
# label
|
16
|
+
# multipart=
|
17
|
+
# new
|
18
|
+
# radio_button
|
19
|
+
# select
|
20
|
+
# submit
|
21
|
+
# time_select
|
22
|
+
# time_zone_select
|
23
|
+
# to_model
|
24
|
+
# to_partial_path
|
@@ -0,0 +1,267 @@
|
|
1
|
+
optionsNullSelector = (value) ->
|
2
|
+
false
|
3
|
+
|
4
|
+
optionsStringSelectorBuilder = (_reference) ->
|
5
|
+
reference = _reference
|
6
|
+
(value) ->
|
7
|
+
value.toString() && reference == value.toString()
|
8
|
+
|
9
|
+
optionsArraySelectorBuilder = (_reference)->
|
10
|
+
reference = []
|
11
|
+
for index, ref_value of _reference
|
12
|
+
reference.push ref_value.toString()
|
13
|
+
(value) ->
|
14
|
+
value && reference.indexOf(value.toString()) > -1
|
15
|
+
|
16
|
+
disabledAndSelector = (options, selected_selector, disabled_selector) ->
|
17
|
+
options['selected'] = true if selected_selector(options['value'])
|
18
|
+
options['disabled'] = true if disabled_selector(options['value'])
|
19
|
+
|
20
|
+
stringOption = (value, selected_selector, disabled_selector) ->
|
21
|
+
options = { value: value }
|
22
|
+
disabledAndSelector options, selected_selector, disabled_selector
|
23
|
+
@contentTag 'option', @htmlEscape(value), @htmlEscapeAttributes(options)
|
24
|
+
|
25
|
+
selectorForOptions = (reference) ->
|
26
|
+
reference = reference.toString() if typeof reference == 'number' || reference == true || reference == false
|
27
|
+
|
28
|
+
return [ reference, optionsNullSelector ] if typeof reference == 'function'
|
29
|
+
return [ optionsNullSelector, optionsNullSelector ] if reference == null || reference == undefined
|
30
|
+
return [ optionsStringSelectorBuilder(reference), optionsNullSelector ] if typeof reference == 'string'
|
31
|
+
return [ optionsArraySelectorBuilder(reference), optionsNullSelector ] if reference instanceof Array
|
32
|
+
|
33
|
+
[ selectorForOptions( reference['selected'] )[0], selectorForOptions( reference['disabled'] )[0] ]
|
34
|
+
|
35
|
+
collectionValueForSelector = (_selector, value_method) ->
|
36
|
+
selector = _selector
|
37
|
+
(value) ->
|
38
|
+
selector value[value_method]
|
39
|
+
|
40
|
+
selectorForOptionsFromCollection = (reference, _value_method) ->
|
41
|
+
value_method = _value_method
|
42
|
+
reference = reference.toString() if typeof reference == 'number' || reference == true || reference == false
|
43
|
+
|
44
|
+
return [ reference, optionsNullSelector ] if typeof reference == 'function'
|
45
|
+
return [ optionsNullSelector, optionsNullSelector ] if reference == null || reference == undefined
|
46
|
+
return [ collectionValueForSelector(optionsStringSelectorBuilder(reference), value_method), optionsNullSelector ] if typeof reference == 'string'
|
47
|
+
return [ collectionValueForSelector(optionsArraySelectorBuilder(reference), value_method), optionsNullSelector ] if reference instanceof Array
|
48
|
+
|
49
|
+
[ selectorForOptionsFromCollection( reference['selected'], _value_method )[0], selectorForOptionsFromCollection( reference['disabled'], _value_method )[0] ]
|
50
|
+
|
51
|
+
collectionFetcherBlock = (_accessor_method) ->
|
52
|
+
accessor_method = _accessor_method
|
53
|
+
if typeof accessor_method == 'function'
|
54
|
+
accessor_method
|
55
|
+
else
|
56
|
+
(object) ->
|
57
|
+
object[accessor_method]
|
58
|
+
|
59
|
+
extractNamePrefixAndMethod = ((object, method_or_prefix_and_method) ->
|
60
|
+
[ prefix, method ] = if typeof method_or_prefix_and_method == 'string'
|
61
|
+
class_name = object['_class'] || object['_type'] || object['class'] || object['type']
|
62
|
+
if class_name
|
63
|
+
class_name = class_name() if typeof class_name == 'function'
|
64
|
+
[ @underscore(class_name), method_or_prefix_and_method ]
|
65
|
+
else
|
66
|
+
[ null, method_or_prefix_and_method ]
|
67
|
+
else
|
68
|
+
method_or_prefix_and_method
|
69
|
+
|
70
|
+
name = if prefix then prefix + '[' + method + ']' else method
|
71
|
+
[ name, prefix, method ]).bind(this)
|
72
|
+
|
73
|
+
multipleHiddenInput = ((name, options) ->
|
74
|
+
multiple_hidden_input = if options['multiple']
|
75
|
+
name = name + '[]' if name[-2..-1] != '[]'
|
76
|
+
if options['include_hidden'] == true || options['include_hidden'] == undefined
|
77
|
+
@tag 'input', type: 'hidden', name: name, value: '', disabled: options['disabled']
|
78
|
+
else
|
79
|
+
''
|
80
|
+
else
|
81
|
+
''
|
82
|
+
options['include_hidden'] = undefined
|
83
|
+
[ name, multiple_hidden_input ]).bind(this)
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
helper 'optionsForSelect', (container, selectors) ->
|
88
|
+
return container.toString() if typeof container == 'string' || typeof value == 'number' || value == true || value == false
|
89
|
+
return container().toString() if typeof container == 'function'
|
90
|
+
|
91
|
+
[ selected_selector, disabled_selector ] = selectorForOptions selectors
|
92
|
+
|
93
|
+
unless container instanceof Array
|
94
|
+
array_container = []
|
95
|
+
for index, value of container
|
96
|
+
array_container.push [ index, value ]
|
97
|
+
container = array_container
|
98
|
+
|
99
|
+
select_options = ''
|
100
|
+
for index, value of container
|
101
|
+
value = value.toString() if typeof value == 'number' || value == true || value == false
|
102
|
+
value = '' if value == null
|
103
|
+
|
104
|
+
if typeof value == 'string'
|
105
|
+
select_options += stringOption.call(this, value, selected_selector, disabled_selector)
|
106
|
+
if value instanceof Array
|
107
|
+
[ content, value_option, options ] = if value.length == 3
|
108
|
+
[ value[0], value[1], @_clone(value[2]) ]
|
109
|
+
else if value.length == 2
|
110
|
+
if typeof value[1] == 'object'
|
111
|
+
[ value[0], value[0], @_clone(value[1]) ]
|
112
|
+
else
|
113
|
+
[ value[0], value[1], {} ]
|
114
|
+
else
|
115
|
+
[ value[0], value[0], {} ]
|
116
|
+
|
117
|
+
content = content.toString() if typeof content == 'number' || content == true || content == false
|
118
|
+
content ||= ''
|
119
|
+
|
120
|
+
value_option = value_option.toString() if typeof value_option == 'number' || value_option == true || value_option == false
|
121
|
+
options['value'] ||= value_option || content
|
122
|
+
|
123
|
+
disabledAndSelector options, selected_selector, disabled_selector
|
124
|
+
select_options += @contentTag 'option', @htmlEscape(content), @htmlEscapeAttributes(options)
|
125
|
+
|
126
|
+
select_options
|
127
|
+
|
128
|
+
helper 'optionsFromCollectionForSelect', (collection, value_method, text_method, selectors) ->
|
129
|
+
[ selected_selector, disabled_selector ] = selectorForOptionsFromCollection selectors, value_method
|
130
|
+
selectors = { selected: [], disabled: [] }
|
131
|
+
|
132
|
+
text_fetcher = collectionFetcherBlock text_method
|
133
|
+
value_fetcher = collectionFetcherBlock value_method
|
134
|
+
|
135
|
+
container = []
|
136
|
+
for index, object of collection
|
137
|
+
options = if object instanceof Array && object.length == 3
|
138
|
+
object[2]
|
139
|
+
else
|
140
|
+
{}
|
141
|
+
value = value_fetcher object
|
142
|
+
container.push [ text_fetcher(object), value, options ]
|
143
|
+
selectors['selected'].push(value) if selected_selector(object)
|
144
|
+
selectors['disabled'].push(value) if disabled_selector(object)
|
145
|
+
|
146
|
+
@optionsForSelect container, selectors
|
147
|
+
|
148
|
+
helper 'groupedOptionsForSelect', (grouped_options, selectors, options = {}) ->
|
149
|
+
[ selected_selector, disabled_selector ] = selectorForOptions selectors
|
150
|
+
|
151
|
+
options_for_select = ''
|
152
|
+
if options['prompt']
|
153
|
+
prompt = if typeof options['prompt'] == 'string' || options['prompt'] == 'number'
|
154
|
+
options['prompt'].toString()
|
155
|
+
else
|
156
|
+
@translate 'helpers.select.prompt', default: 'Please select'
|
157
|
+
options_for_select += @contentTag( 'option', @htmlEscape(prompt), { value: '' } )
|
158
|
+
|
159
|
+
for index, options_in_group of grouped_options
|
160
|
+
[ options_in_group, optgroup_options ] = if options['divider']
|
161
|
+
if grouped_options instanceof Array
|
162
|
+
[ options_in_group, { label: options['divider'] } ]
|
163
|
+
else
|
164
|
+
if grouped_options instanceof Array
|
165
|
+
optgroup_options = options_in_group[2] || {}
|
166
|
+
optgroup_options['label'] = options_in_group[0]
|
167
|
+
[ options_in_group[1], optgroup_options ]
|
168
|
+
else
|
169
|
+
[ options_in_group, { label: index } ]
|
170
|
+
|
171
|
+
options_for_select += @contentTag('optgroup', @optionsForSelect(options_in_group, selectors), @htmlEscapeAttributes(optgroup_options) )
|
172
|
+
|
173
|
+
options_for_select
|
174
|
+
|
175
|
+
helper 'optionGroupsFromCollectionForSelect', (collection, group_method, group_label_method, option_key_method, option_value_method, selectors) ->
|
176
|
+
group_fetcher = collectionFetcherBlock group_method
|
177
|
+
group_label_fetcher = collectionFetcherBlock group_label_method
|
178
|
+
|
179
|
+
options_for_select = ''
|
180
|
+
for index, object of collection
|
181
|
+
options_for_select += @contentTag('optgroup', @optionsFromCollectionForSelect(group_fetcher(object), option_key_method, option_value_method, selectors), { label: @htmlEscape( group_label_fetcher object ) } )
|
182
|
+
|
183
|
+
options_for_select
|
184
|
+
|
185
|
+
# EXPLAIN: When object is a Ruby object, two things can happen:
|
186
|
+
# 1. If it don't responds to method [], class if infered by .class method
|
187
|
+
# 2. If it responds to method [], class is infered by object['_class'] || object['_type'] || object['class'] || object['type'] in that order
|
188
|
+
#
|
189
|
+
# IMPORTANT: Removed 'required' option, it seems too much cryptic to be used
|
190
|
+
# TODO: Add index option
|
191
|
+
helper 'selectForObject', (object, method_or_prefix_and_method, choices_or_options, options_or_choices) ->
|
192
|
+
[ name, prefix, method ] = extractNamePrefixAndMethod object, method_or_prefix_and_method
|
193
|
+
|
194
|
+
[ choices, options ] = if typeof options_or_choices == 'function'
|
195
|
+
[ options_or_choices, @_clone( choices_or_options || {} ) ]
|
196
|
+
else
|
197
|
+
[ choices_or_options, @_clone( options_or_choices || {} ) ]
|
198
|
+
|
199
|
+
[ name, multiple_hidden_input ] = multipleHiddenInput name, options
|
200
|
+
|
201
|
+
# reference = options['selected'] || object[method]
|
202
|
+
# options['selected'] = undefined
|
203
|
+
# pre_selector = selectorForOptions( reference )[0]
|
204
|
+
# selector = (value) ->
|
205
|
+
# selected = pre_selector value
|
206
|
+
# # Welcome black magic!
|
207
|
+
# options['prompt'] = undefined if selected
|
208
|
+
# selected
|
209
|
+
|
210
|
+
selector = if options['selected'] == null
|
211
|
+
undefined
|
212
|
+
else
|
213
|
+
reference = options['selected'] || object[method]
|
214
|
+
pre_selector = selectorForOptions( reference )[0]
|
215
|
+
(value) ->
|
216
|
+
selected = pre_selector value
|
217
|
+
# Welcome black magic!
|
218
|
+
options['prompt'] = undefined if selected
|
219
|
+
selected
|
220
|
+
options['selected'] = undefined
|
221
|
+
|
222
|
+
if typeof choices == 'object'
|
223
|
+
unless choices instanceof Array
|
224
|
+
array_choices = []
|
225
|
+
for index, value of choices
|
226
|
+
array_choices.push [ index, value ]
|
227
|
+
choices = array_choices
|
228
|
+
|
229
|
+
if choices[1] instanceof Array
|
230
|
+
choices_options = {}
|
231
|
+
choices_options['divider'] = options['divider'] unless options['divider'] == undefined
|
232
|
+
options['divider'] = undefined
|
233
|
+
return multiple_hidden_input + @selectTag(name, @groupedOptionsForSelect(choices, selector, choices_options), options)
|
234
|
+
|
235
|
+
multiple_hidden_input + @selectTag(name, @optionsForSelect(choices, selector), options)
|
236
|
+
|
237
|
+
helper 'collectionSelectForObject', (object, method_or_prefix_and_method, collection, value_method, text_method, options)->
|
238
|
+
[ name, prefix, method ] = extractNamePrefixAndMethod object, method_or_prefix_and_method
|
239
|
+
|
240
|
+
options = if options != undefined then @_clone(options) else {}
|
241
|
+
|
242
|
+
[ name, multiple_hidden_input ] = multipleHiddenInput name, options
|
243
|
+
|
244
|
+
selector = if options['selected'] == null
|
245
|
+
undefined
|
246
|
+
else
|
247
|
+
reference = options['selected'] || object[method]
|
248
|
+
pre_selector = selectorForOptionsFromCollection( reference, value_method )[0]
|
249
|
+
(value) ->
|
250
|
+
selected = pre_selector value
|
251
|
+
# Welcome black magic!
|
252
|
+
options['prompt'] = undefined if selected
|
253
|
+
selected
|
254
|
+
options['selected'] = undefined
|
255
|
+
|
256
|
+
choices = @optionsFromCollectionForSelect collection, value_method, text_method, selector
|
257
|
+
multiple_hidden_input + @selectTag(name, choices, options)
|
258
|
+
|
259
|
+
# TODO: Finish form_options helpers
|
260
|
+
# collection_check_boxes
|
261
|
+
# collection_radio_buttons
|
262
|
+
# collection_select
|
263
|
+
# grouped_collection_select
|
264
|
+
|
265
|
+
# TODO: Think about implementing or not time zone helpers
|
266
|
+
# time_zone_options_for_select
|
267
|
+
# time_zone_select
|
@@ -0,0 +1,204 @@
|
|
1
|
+
sanitizeToId = (name) ->
|
2
|
+
name = name.toString()
|
3
|
+
name = name[0..-3] if name[-2..-1] == '[]'
|
4
|
+
name.replace(/\]/g, '').replace /[^-a-zA-Z0-9:.]/g, '_'
|
5
|
+
|
6
|
+
humanizeToLabel = (name) ->
|
7
|
+
sanitized = name.toString().replace(/\]/g, '').replace /[^-a-zA-Z0-9:.]/g, ' '
|
8
|
+
sanitized[0].toUpperCase() + sanitized.slice(1);
|
9
|
+
|
10
|
+
fieldTagBuilder = (_type) ->
|
11
|
+
type = _type
|
12
|
+
(name, value = null, options = {}) ->
|
13
|
+
html_options = @_clone options
|
14
|
+
html_options['type'] = type
|
15
|
+
html_options['name'] = name
|
16
|
+
html_options['id'] = sanitizeToId(name) if html_options['id'] == undefined
|
17
|
+
html_options['value'] ||= value if value
|
18
|
+
@tag 'input', html_options
|
19
|
+
|
20
|
+
for i, type of ['color', 'date', 'datetime', 'email', 'file', 'hidden', 'month', 'number', 'password', 'range', 'search', 'text', 'time', 'url', 'week']
|
21
|
+
helper (type+'FieldTag'), fieldTagBuilder.call(this, type)
|
22
|
+
|
23
|
+
helper 'datetimeLocalFieldTag', fieldTagBuilder.call(this, 'datetime-local')
|
24
|
+
helper 'telephoneFieldTag', fieldTagBuilder.call(this, 'tel')
|
25
|
+
|
26
|
+
alias 'phoneFieldTag', 'telephoneFieldTag'
|
27
|
+
|
28
|
+
helper 'buttonTag', (content_or_options = null, options_or_content = {}) ->
|
29
|
+
[content, options] = @_contentOrOptions content_or_options, options_or_content
|
30
|
+
|
31
|
+
content = content.call(this) if typeof content == 'function'
|
32
|
+
options['name'] ||= 'button'
|
33
|
+
options['type'] ||= 'submit'
|
34
|
+
@contentTag 'button', (content || 'Button'), options
|
35
|
+
|
36
|
+
helper 'checkBoxTag', (name, value = 1, checked = false, options = {}) ->
|
37
|
+
html_options = @_clone options
|
38
|
+
html_options['type'] = 'checkbox'
|
39
|
+
html_options['name'] = name
|
40
|
+
html_options['value'] = value
|
41
|
+
html_options['checked'] = 'checked' if checked
|
42
|
+
html_options['id'] = sanitizeToId(name) if html_options['id'] == undefined
|
43
|
+
@tag 'input', html_options
|
44
|
+
alias 'checkboxTag', 'checkBoxTag'
|
45
|
+
|
46
|
+
helper 'fieldSetTag', (legend = null, content_or_options = '', options_or_content = {}) ->
|
47
|
+
[content, options] = if typeof legend == 'function'
|
48
|
+
content_and_options = [ legend, {} ]
|
49
|
+
legend = null
|
50
|
+
content_and_options
|
51
|
+
else
|
52
|
+
@_contentOrOptions content_or_options, options_or_content, ''
|
53
|
+
|
54
|
+
content = content.call(this) if typeof content == 'function'
|
55
|
+
content = @contentTag('legend', legend) + content if legend && legend != ''
|
56
|
+
@contentTag 'fieldset', content, options
|
57
|
+
|
58
|
+
alias 'fieldsetTag', 'fieldSetTag'
|
59
|
+
|
60
|
+
buildFormOptions = (url, options) ->
|
61
|
+
method = (options['method'] || 'post').toLowerCase()
|
62
|
+
options['action'] = url
|
63
|
+
options['method'] = if method == 'get' then 'get' else 'post'
|
64
|
+
options['accept-charset'] ||= 'UTF-8'
|
65
|
+
|
66
|
+
if options['multipart']
|
67
|
+
options['enctype'] = 'multipart/form-data'
|
68
|
+
options['multipart'] = undefined
|
69
|
+
|
70
|
+
options['data-remote'] = 'true' if options['remote']
|
71
|
+
options['remote'] = undefined
|
72
|
+
|
73
|
+
enforce_utf8 = options['enforce_utf8'] == undefined || options['enforce_utf8']
|
74
|
+
options['enforce_utf8'] = undefined
|
75
|
+
|
76
|
+
authenticity_token = if ( @_context.protectFromForgery && options['authenticity_token'] == undefined ) || options['authenticity_token']
|
77
|
+
if options['authenticity_token'] == undefined || options['authenticity_token'] == true then @csrfToken else options['authenticity_token']
|
78
|
+
else
|
79
|
+
false
|
80
|
+
options['authenticity_token'] = undefined
|
81
|
+
|
82
|
+
[ method, enforce_utf8, authenticity_token ]
|
83
|
+
|
84
|
+
buildFormContent = (content, method, enforce_utf8, authenticity_token) ->
|
85
|
+
form_content = ''
|
86
|
+
|
87
|
+
method_enforcer = method != 'get' && method != 'post'
|
88
|
+
form_content += '<div style="display:none">'
|
89
|
+
if enforce_utf8 || authenticity_token || method_enforcer
|
90
|
+
form_content += @utf8EnforcerTag() if enforce_utf8
|
91
|
+
form_content += @methodHiddenTag(method) if method_enforcer
|
92
|
+
form_content += @authenticityTokenTag(authenticity_token) if authenticity_token
|
93
|
+
form_content += '</div>'
|
94
|
+
|
95
|
+
content = content.call(this) if typeof content == 'function'
|
96
|
+
|
97
|
+
form_content + content
|
98
|
+
|
99
|
+
helper 'formTag', (url = '/', content_or_options, options_or_content) ->
|
100
|
+
[content, options] = if typeof url == 'function'
|
101
|
+
content_and_options = [url, {}]
|
102
|
+
url = '/'
|
103
|
+
content_and_options
|
104
|
+
else
|
105
|
+
@_contentOrOptions content_or_options, options_or_content, ''
|
106
|
+
|
107
|
+
[ method, enforce_utf8, authenticity_token ] = buildFormOptions.call this, url, options
|
108
|
+
|
109
|
+
@contentTag 'form', buildFormContent.call(this, content, method, enforce_utf8, authenticity_token), options
|
110
|
+
|
111
|
+
helper 'imageSubmitTag', (source, options = {}) ->
|
112
|
+
options = @_clone options
|
113
|
+
options['src'] ||= @imagePath source
|
114
|
+
options['type'] ||= 'image'
|
115
|
+
options['alt'] ||= @imageAlt source
|
116
|
+
@tag 'input', options
|
117
|
+
|
118
|
+
helper 'labelTag', (name, content_or_options = null, options_or_content = {}) ->
|
119
|
+
[content, options] = if typeof name == 'function'
|
120
|
+
content_and_options = [name, {}]
|
121
|
+
name = null
|
122
|
+
content_and_options
|
123
|
+
else
|
124
|
+
@_contentOrOptions content_or_options, options_or_content
|
125
|
+
|
126
|
+
content ||= humanizeToLabel name
|
127
|
+
options['for'] ||= sanitizeToId(name) if name
|
128
|
+
@contentTag 'label', content, options
|
129
|
+
|
130
|
+
helper 'radioButtonTag', (name, value, checked = false, options = {}) ->
|
131
|
+
options = @_clone options
|
132
|
+
options['type'] = 'radio'
|
133
|
+
options['name'] = name
|
134
|
+
options['value'] = value
|
135
|
+
options['checked'] = 'checked' if checked
|
136
|
+
options['id'] ||= sanitizeToId(name) + '_' + sanitizeToId(value)
|
137
|
+
@tag 'input', options
|
138
|
+
|
139
|
+
helper 'selectTag', (name, option_tags = '', options = {}) ->
|
140
|
+
options = @_clone options
|
141
|
+
|
142
|
+
if options['include_blank']
|
143
|
+
blank_content = if options['include_blank'] == true then '' else @htmlEscape( options['include_blank'] )
|
144
|
+
option_tags = @contentTag('option', blank_content, value: '') + option_tags
|
145
|
+
options['include_blank'] = undefined
|
146
|
+
|
147
|
+
if options['prompt']
|
148
|
+
prompt_content = if options['prompt'] == true then @translate('helpers.select.prompt', default: 'Please select') else @htmlEscape( options['prompt'] )
|
149
|
+
option_tags = @contentTag('option', prompt_content, value: '') + option_tags
|
150
|
+
options['prompt'] = undefined
|
151
|
+
|
152
|
+
html_name = if options['multiple']
|
153
|
+
unless name.toString()[-2..-1] == '[]'
|
154
|
+
name + '[]'
|
155
|
+
else
|
156
|
+
name
|
157
|
+
|
158
|
+
options['multiple'] = undefined if options['multiple'] == false
|
159
|
+
|
160
|
+
options['id'] = sanitizeToId(name) if options['id'] == undefined
|
161
|
+
options['name'] ||= name
|
162
|
+
@contentTag 'select', option_tags, options
|
163
|
+
|
164
|
+
helper 'submitTag', (value = "Save changes", options = {}) ->
|
165
|
+
options = @_clone options
|
166
|
+
options['type'] ||= 'submit'
|
167
|
+
options['name'] ||= 'commit'
|
168
|
+
options['value'] ||= value
|
169
|
+
@tag 'input', options
|
170
|
+
|
171
|
+
handleSizeAttribute = (options) ->
|
172
|
+
if typeof options['size'] == 'string'
|
173
|
+
size = options['size'].toLowerCase()
|
174
|
+
if (/\d+X\d+/i).test(size)
|
175
|
+
xIndex = size.lastIndexOf('x');
|
176
|
+
options['cols'] ||= size.substring 0, xIndex
|
177
|
+
options['rows'] ||= size.substring xIndex+1
|
178
|
+
options['size'] = undefined
|
179
|
+
|
180
|
+
helper 'textAreaTag', (name, content_or_options = '', options_or_content = {}) ->
|
181
|
+
[content, options] = @_contentOrOptions content_or_options, options_or_content
|
182
|
+
handleSizeAttribute options
|
183
|
+
|
184
|
+
content = content.call(this) if typeof content == 'function'
|
185
|
+
content ||= ''
|
186
|
+
|
187
|
+
if typeof options['escape'] == 'undefined' || options['escape']
|
188
|
+
content = @htmlEscape content
|
189
|
+
options['escape'] = undefined
|
190
|
+
|
191
|
+
options['id'] = sanitizeToId(name) if options['id'] == undefined
|
192
|
+
options['name'] ||= name
|
193
|
+
@contentTag 'textarea', "\n"+content, options
|
194
|
+
|
195
|
+
alias 'textareaTag', 'textAreaTag'
|
196
|
+
|
197
|
+
helper 'authenticityTokenTag', (authenticity_token) ->
|
198
|
+
@tag 'input', type: 'hidden', name: @_context.requestForgeryProtectionToken, value: authenticity_token
|
199
|
+
|
200
|
+
helper 'methodHiddenTag', (method) ->
|
201
|
+
@tag 'input', type: 'hidden', name: '_method', value: method
|
202
|
+
|
203
|
+
helper 'utf8EnforcerTag', () ->
|
204
|
+
@tag 'input', type: 'hidden', name: 'utf8', value: "✓"
|