ultimate-base 0.3.1.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +15 -15
- data/app/assets/javascripts/ultimate/backbone/lib/backbone.js +70 -56
- data/app/assets/javascripts/ultimate/backbone/model.js.coffee +2 -2
- data/app/assets/javascripts/ultimate/backbone/view.js.coffee +5 -4
- data/app/assets/javascripts/ultimate/backbone/views/typed-fields.js.coffee +1 -1
- data/app/assets/javascripts/ultimate/helpers/asset_tag.js.coffee +21 -19
- data/app/assets/javascripts/ultimate/helpers/form_options.js.coffee +65 -0
- data/app/assets/javascripts/ultimate/helpers/form_tag.js.coffee +177 -0
- data/app/assets/javascripts/ultimate/helpers/javascript.js.coffee +31 -0
- data/app/assets/javascripts/ultimate/helpers/record_tag.js.coffee +29 -15
- data/app/assets/javascripts/ultimate/helpers/tag.js.coffee +7 -3
- data/app/assets/javascripts/ultimate/helpers/url.js.coffee +62 -7
- data/app/assets/javascripts/ultimate/jquery-plugin-adapter.js.coffee +1 -0
- data/app/assets/javascripts/ultimate/jquery-plugin-class.js.coffee +35 -16
- data/app/assets/javascripts/ultimate/jquery.base.js.coffee +1 -1
- data/app/assets/javascripts/ultimate/underscore/underscore.js +292 -192
- data/app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee +27 -2
- data/app/assets/javascripts/ultimate/underscore/underscore.string.js +4 -4
- data/app/assets/stylesheets/polyfills/PIE.htc +81 -81
- data/app/assets/stylesheets/polyfills/boxsizing.htc +255 -54
- data/app/assets/stylesheets/ultimate/mixins/_vendors.scss +9 -0
- data/app/assets/stylesheets/ultimate/mixins/css3.scss +39 -28
- data/app/assets/stylesheets/ultimate/mixins/microstructures.scss +32 -6
- data/lib/ultimate/base/version.rb +1 -1
- data/test/javascripts/tests/helpers/asset_tag_test.js.coffee +1 -1
- data/test/javascripts/tests/helpers/form_options_test.js.coffee +96 -0
- data/test/javascripts/tests/helpers/form_tag_test.js.coffee +225 -0
- data/test/javascripts/tests/helpers/javascript_test.js.coffee +25 -0
- data/test/javascripts/tests/helpers/record_tag_test.js.coffee +5 -3
- data/test/javascripts/tests/helpers/tag_test.js.coffee +22 -17
- data/test/javascripts/tests/helpers/url_test.js.coffee +50 -6
- data/test/javascripts/tests/underscore/underscore.outcasts.test.js.coffee +9 -0
- metadata +8 -4
- data/app/assets/javascripts/ultimate/helpers/translation.js.coffee +0 -97
- data/test/javascripts/tests/helpers/translation_test.js.coffee +0 -140
@@ -0,0 +1,65 @@
|
|
1
|
+
#= require ./base
|
2
|
+
#= require ./tag
|
3
|
+
|
4
|
+
@Ultimate.Helpers.FormOptions =
|
5
|
+
|
6
|
+
options_for_select: (container, selected = null) ->
|
7
|
+
return container if _.isString(container)
|
8
|
+
[selected, disabled] = _.map @_extract_selected_and_disabled(selected), (r) ->
|
9
|
+
_.map _.outcasts.arrayWrap(r), (item) -> item.toString()
|
10
|
+
container = _.pairs(container) if $.isPlainObject(container)
|
11
|
+
_.map(container, (element) ->
|
12
|
+
html_attributes = @_option_html_attributes(element)
|
13
|
+
[text, value] = _.map @_option_text_and_value(element), (item) -> if item? then item.toString() else ''
|
14
|
+
html_attributes['value'] = value
|
15
|
+
html_attributes['selected'] = 'selected' if @_option_value_selected(value, selected)
|
16
|
+
html_attributes['disabled'] = 'disabled' if disabled and @_option_value_selected(value, disabled)
|
17
|
+
Ultimate.Helpers.Tag.content_tag_string 'option', text, html_attributes
|
18
|
+
).join("\n")
|
19
|
+
|
20
|
+
options_from_collection_for_select: (collection, value_method, text_method, selected = null) ->
|
21
|
+
options = _.map collection, (element) ->
|
22
|
+
[@_value_for_collection(element, text_method), @_value_for_collection(element, value_method)]
|
23
|
+
[selected, disabled] = @_extract_selected_and_disabled(selected)
|
24
|
+
select_deselect =
|
25
|
+
selected: @_extract_values_from_collection(collection, value_method, selected)
|
26
|
+
disabled: @_extract_values_from_collection(collection, value_method, disabled)
|
27
|
+
@options_for_select(options, select_deselect)
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
_option_html_attributes: (element) ->
|
32
|
+
result = {}
|
33
|
+
if _.isArray(element)
|
34
|
+
_.extend(result, e) for e in element when $.isPlainObject(e)
|
35
|
+
result
|
36
|
+
|
37
|
+
_option_text_and_value: (option) ->
|
38
|
+
# Options are [text, value] pairs or strings used for both.
|
39
|
+
if _.isArray(option)
|
40
|
+
option = _.reject(option, (e) -> $.isPlainObject(e))
|
41
|
+
[_.first(option), _.last(option)]
|
42
|
+
else
|
43
|
+
[option, option]
|
44
|
+
|
45
|
+
_option_value_selected: (value, selected) ->
|
46
|
+
value in selected
|
47
|
+
|
48
|
+
_extract_selected_and_disabled: (selected) ->
|
49
|
+
if _.isFunction(selected)
|
50
|
+
[selected, null]
|
51
|
+
else
|
52
|
+
selected = _.outcasts.arrayWrap(selected)
|
53
|
+
options = if $.isPlainObject(_.last(selected)) then selected.pop() else {}
|
54
|
+
selected_items = options['selected'] ? selected
|
55
|
+
[selected_items, options['disabled']]
|
56
|
+
|
57
|
+
_extract_values_from_collection: (collection, value_method, selected) ->
|
58
|
+
if _.isFunction(selected)
|
59
|
+
_.compact _.map collection, (element) ->
|
60
|
+
_.result(element, value_method) if selected(element)
|
61
|
+
else
|
62
|
+
selected
|
63
|
+
|
64
|
+
_value_for_collection: (item, value) ->
|
65
|
+
if _.isFunction(value) then value(item) else _.result(item, value)
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#= require ./base
|
2
|
+
#= require ./tag
|
3
|
+
#= require ./url
|
4
|
+
#= require ./asset_tag
|
5
|
+
|
6
|
+
@Ultimate.Helpers.FormTag =
|
7
|
+
|
8
|
+
embed_authenticity_token_in_remote_forms: false
|
9
|
+
|
10
|
+
form_tag: (url_for_options = {}, options = {}, block = null) ->
|
11
|
+
html_options = @_html_options_for_form(url_for_options, options)
|
12
|
+
if block = _.outcasts.blockGiven(arguments)
|
13
|
+
@_form_tag_in_block(html_options, block)
|
14
|
+
else
|
15
|
+
@_form_tag_html(html_options)
|
16
|
+
|
17
|
+
select_tag: (name, option_tags = '', options = {}) ->
|
18
|
+
html_name = if options.multiple is true and not _.string.endsWith(name, '[]') then "#{name}[]" else name
|
19
|
+
if _.outcasts.delete(options, 'include_blank')
|
20
|
+
option_tags = Ultimate.Helpers.Tag.content_tag('option', '', value: '') + option_tags
|
21
|
+
if prompt = _.outcasts.delete(options, 'prompt')
|
22
|
+
option_tags = Ultimate.Helpers.Tag.content_tag('option', prompt, value: '') + option_tags
|
23
|
+
Ultimate.Helpers.Tag.content_tag 'select', option_tags, _.extend({name: html_name, id: @_sanitize_to_id(name)}, options), false
|
24
|
+
|
25
|
+
text_field_tag: (name, value = null, options = {}) ->
|
26
|
+
Ultimate.Helpers.Tag.tag 'input', _.extend({type: 'text', name: name, id: @_sanitize_to_id(name), value: value}, options)
|
27
|
+
|
28
|
+
label_tag: (name = null, content_or_options = null, options = null, block = null) ->
|
29
|
+
if (block = _.outcasts.blockGiven(arguments)) and $.isPlainObject(content_or_options)
|
30
|
+
options = content_or_options
|
31
|
+
else
|
32
|
+
options ||= {}
|
33
|
+
if _.isString(name) and not _.string.isBlank(name)
|
34
|
+
unless _.has(options, 'for')
|
35
|
+
options = _.clone(options)
|
36
|
+
options['for'] = @_sanitize_to_id(name)
|
37
|
+
content_or_options ||= _.string.humanize(name)
|
38
|
+
content_or_options = options if block
|
39
|
+
Ultimate.Helpers.Tag.content_tag 'label', content_or_options, options, block
|
40
|
+
|
41
|
+
hidden_field_tag: (name, value = null, options = {}) ->
|
42
|
+
@text_field_tag name, value, _.extend(options, type: 'hidden')
|
43
|
+
|
44
|
+
file_field_tag: (name, options = {}) ->
|
45
|
+
@text_field_tag name, null, _.extend(options, type: 'file')
|
46
|
+
|
47
|
+
password_field_tag: (name = 'password', value = null, options = {}) ->
|
48
|
+
@text_field_tag name, value, _.extend(options, type: 'password')
|
49
|
+
|
50
|
+
text_area_tag: (name, content = null, options = {}) ->
|
51
|
+
if size = _.outcasts.delete(options, 'size')
|
52
|
+
[options['cols'], options['rows']] = size.split("x") if _.isFunction(size.split)
|
53
|
+
escape = _.outcasts.delete(options, 'escape') ? true
|
54
|
+
Ultimate.Helpers.Tag.content_tag 'textarea', content, _.extend({name: name, id: @_sanitize_to_id(name)}, options), escape
|
55
|
+
|
56
|
+
check_box_tag: (name, value = '1', checked = false, options = {}) ->
|
57
|
+
html_options = _.extend({type: 'checkbox', name: name, id: @_sanitize_to_id(name), value: value}, options)
|
58
|
+
html_options['checked'] = 'checked' if checked
|
59
|
+
Ultimate.Helpers.Tag.tag 'input', html_options
|
60
|
+
|
61
|
+
radio_button_tag: (name, value, checked = false, options = {}) ->
|
62
|
+
html_options = _.extend({type: 'radio', name: name, id: "#{@_sanitize_to_id(name)}_#{@_sanitize_to_id(value)}", value: value}, options)
|
63
|
+
html_options['checked'] = 'checked' if checked
|
64
|
+
Ultimate.Helpers.Tag.tag 'input', html_options
|
65
|
+
|
66
|
+
submit_tag: (value = 'Save changes', options = {}) ->
|
67
|
+
Ultimate.Helpers.Tag.tag 'input', _.extend({type: 'submit', name: 'commit', value: value}, options)
|
68
|
+
|
69
|
+
button_tag: (content_or_options = null, options = null, block = null) ->
|
70
|
+
options = content_or_options if (block = _.outcasts.blockGiven(arguments)) and $.isPlainObject(content_or_options)
|
71
|
+
options ||= {}
|
72
|
+
options = _.extend({name: 'button', type: 'submit'}, options)
|
73
|
+
content_or_options = options if block
|
74
|
+
Ultimate.Helpers.Tag.content_tag 'button', content_or_options ? 'Button', options, not block, block
|
75
|
+
|
76
|
+
image_submit_tag: (source, options = {}) ->
|
77
|
+
Ultimate.Helpers.Tag.tag 'input', _.extend({type: 'image', src: Ultimate.Helpers.AssetTag.path_to_image(source)}, options)
|
78
|
+
|
79
|
+
field_set_tag: (legend = null, options = null, block) ->
|
80
|
+
output = Ultimate.Helpers.Tag.tag('fieldset', options, true)
|
81
|
+
output += Ultimate.Helpers.Tag.content_tag('legend', legend) if _.isString(legend) and not _.string.isBlank(legend)
|
82
|
+
output += block() if block = _.outcasts.blockGiven(arguments)
|
83
|
+
output += '</fieldset>'
|
84
|
+
output
|
85
|
+
|
86
|
+
color_field_tag: (name, value = null, options = {}) ->
|
87
|
+
@text_field_tag name, value, _.extend(options, type: 'color')
|
88
|
+
|
89
|
+
search_field_tag: (name, value = null, options = {}) ->
|
90
|
+
@text_field_tag name, value, _.extend(options, type: 'search')
|
91
|
+
|
92
|
+
telephone_field_tag: (name, value = null, options = {}) ->
|
93
|
+
@text_field_tag name, value, _.extend(options, type: 'tel')
|
94
|
+
|
95
|
+
phone_field_tag: ->
|
96
|
+
@telephone_field_tag arguments...
|
97
|
+
|
98
|
+
date_field_tag: (name, value = null, options = {}) ->
|
99
|
+
@text_field_tag name, value, _.extend(options, type: 'date')
|
100
|
+
|
101
|
+
time_field_tag: (name, value = null, options = {}) ->
|
102
|
+
@text_field_tag name, value, _.extend(options, type: 'time')
|
103
|
+
|
104
|
+
datetime_field_tag: (name, value = null, options = {}) ->
|
105
|
+
@text_field_tag name, value, _.extend(options, type: 'datetime')
|
106
|
+
|
107
|
+
datetime_local_field_tag: (name, value = null, options = {}) ->
|
108
|
+
@text_field_tag name, value, _.extend(options, type: 'datetime-local')
|
109
|
+
|
110
|
+
month_field_tag: (name, value = null, options = {}) ->
|
111
|
+
@text_field_tag name, value, _.extend(options, type: 'month')
|
112
|
+
|
113
|
+
week_field_tag: (name, value = null, options = {}) ->
|
114
|
+
@text_field_tag name, value, _.extend(options, type: 'week')
|
115
|
+
|
116
|
+
url_field_tag: (name, value = null, options = {}) ->
|
117
|
+
@text_field_tag name, value, _.extend(options, type: 'url')
|
118
|
+
|
119
|
+
email_field_tag: (name, value = null, options = {}) ->
|
120
|
+
@text_field_tag name, value, _.extend(options, type: 'email')
|
121
|
+
|
122
|
+
number_field_tag: (name, value = null, options = {}) ->
|
123
|
+
options['type'] ||= 'number'
|
124
|
+
if range = _.outcasts.delete(options, 'in') or _.outcasts.delete(options, 'within')
|
125
|
+
_.extend options, min: range.min, max: range.max
|
126
|
+
@text_field_tag name, value, options
|
127
|
+
|
128
|
+
range_field_tag: (name, value = null, options = {}) ->
|
129
|
+
@number_field_tag name, value, _.extend(options, type: 'range')
|
130
|
+
|
131
|
+
utf8_enforcer_tag: ->
|
132
|
+
Ultimate.Helpers.Tag.tag 'input', type: 'hidden', name: 'utf8', value: '✓', false, false
|
133
|
+
|
134
|
+
_html_options_for_form: (url_for_options, options) ->
|
135
|
+
html_options = options
|
136
|
+
html_options['enctype'] = 'multipart/form-data' if _.outcasts.delete(html_options, 'multipart')
|
137
|
+
# The following URL is unescaped, this is just a hash of options, and it is the
|
138
|
+
# responsibility of the caller to escape all the values.
|
139
|
+
html_options['action'] = Ultimate.Helpers.Url.url_for(url_for_options)
|
140
|
+
html_options['accept-charset'] = 'UTF-8'
|
141
|
+
html_options['data-remote'] = true if _.outcasts.delete(html_options, 'remote')
|
142
|
+
if html_options['data-remote'] and
|
143
|
+
not @embed_authenticity_token_in_remote_forms and
|
144
|
+
_.string.isBlank(html_options['authenticity_token'])
|
145
|
+
# The authenticity token is taken from the meta tag in this case
|
146
|
+
html_options['authenticity_token'] = false
|
147
|
+
else if html_options['authenticity_token'] is true
|
148
|
+
# Include the default authenticity_token, which is only generated when its set to nil,
|
149
|
+
# but we needed the true value to override the default of no authenticity_token on data-remote.
|
150
|
+
html_options['authenticity_token'] = null
|
151
|
+
html_options
|
152
|
+
|
153
|
+
_extra_tags_for_form: (html_options) ->
|
154
|
+
authenticity_token = _.outcasts.delete(html_options, 'authenticity_token')
|
155
|
+
method = _.outcasts.delete(html_options, 'method')
|
156
|
+
method_tag =
|
157
|
+
if /^get$/i.test(method) # must be case-insensitive, but can't use downcase as might be nil
|
158
|
+
html_options['method'] = 'get'
|
159
|
+
''
|
160
|
+
else if _.string.isBlank(method) or /^post$/i.test(method)
|
161
|
+
html_options['method'] = 'post'
|
162
|
+
Ultimate.Helpers.Url._token_tag(authenticity_token)
|
163
|
+
else
|
164
|
+
html_options['method'] = 'post'
|
165
|
+
Ultimate.Helpers.Url._method_tag(method) + Ultimate.Helpers.Url._token_tag(authenticity_token)
|
166
|
+
tags = @utf8_enforcer_tag() + method_tag
|
167
|
+
Ultimate.Helpers.Tag.content_tag('div', tags, style: 'margin:0;padding:0;display:inline', false)
|
168
|
+
|
169
|
+
_form_tag_html: (html_options) ->
|
170
|
+
extra_tags = @_extra_tags_for_form(html_options)
|
171
|
+
Ultimate.Helpers.Tag.tag('form', html_options, true) + extra_tags
|
172
|
+
|
173
|
+
_form_tag_in_block: (html_options, block) ->
|
174
|
+
"#{@_form_tag_html(html_options)}#{block()}</form>"
|
175
|
+
|
176
|
+
_sanitize_to_id: (name) ->
|
177
|
+
if name? then name.toString().replace(/\]/g, '').replace(/[^-a-zA-Z0-9:.]/g, '_') else ''
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#= require ./base
|
2
|
+
#= require ./tag
|
3
|
+
|
4
|
+
JS_ESCAPE_MAP =
|
5
|
+
'\\' : '\\\\'
|
6
|
+
'</' : '<\\/'
|
7
|
+
"\r\n" : '\\n'
|
8
|
+
"\n" : '\\n'
|
9
|
+
"\r" : '\\n'
|
10
|
+
'"' : '\\"'
|
11
|
+
"'" : "\\'"
|
12
|
+
|
13
|
+
@Ultimate.Helpers.Javascript =
|
14
|
+
|
15
|
+
escape_javascript: (javascript) ->
|
16
|
+
return '' unless _.isString(javascript)
|
17
|
+
javascript.replace( /(\\|<\/|\r\n|[\n\r"'])/g, (match) -> JS_ESCAPE_MAP[match] )
|
18
|
+
|
19
|
+
j: -> @escape_javascript arguments...
|
20
|
+
|
21
|
+
javascript_tag: (content_or_options_with_block = null, html_options = {}, block = null) ->
|
22
|
+
content =
|
23
|
+
if block = _.outcasts.blockGiven(arguments)
|
24
|
+
html_options = content_or_options_with_block if $.isPlainObject(content_or_options_with_block)
|
25
|
+
block()
|
26
|
+
else
|
27
|
+
content_or_options_with_block
|
28
|
+
Ultimate.Helpers.Tag.content_tag 'script', @javascript_cdata_section(content), html_options, false
|
29
|
+
|
30
|
+
javascript_cdata_section: (content) ->
|
31
|
+
"\n//#{Ultimate.Helpers.Tag.cdata_section("\n#{content}\n//")}\n"
|
@@ -21,11 +21,21 @@
|
|
21
21
|
options = if _.isObject(options) then _.clone(options) else {}
|
22
22
|
_.extend options, {class: Ultimate.Helpers.Tag.concat_class(@dom_class(record, prefix), options['class']), id: @dom_id(record, prefix)}
|
23
23
|
if block
|
24
|
-
Ultimate.Helpers.Tag.content_tag(tag_name, block(record), options)
|
24
|
+
Ultimate.Helpers.Tag.content_tag(tag_name, block(record), options, false)
|
25
25
|
else
|
26
|
-
Ultimate.Helpers.Tag.content_tag(tag_name, block, options)
|
26
|
+
Ultimate.Helpers.Tag.content_tag(tag_name, block, options, false)
|
27
27
|
|
28
|
-
|
28
|
+
|
29
|
+
|
30
|
+
# from ActionView::ModelNaming
|
31
|
+
model_name_from_record_or_class: (record_or_class) ->
|
32
|
+
modelClass = record_or_class.constructor ? record_or_class
|
33
|
+
if modelClass?
|
34
|
+
modelClass.modelName or modelClass.className or modelClass.name or 'Model'
|
35
|
+
else
|
36
|
+
'Model'
|
37
|
+
|
38
|
+
# ============= from ActionView::RecordIdentifier ===============
|
29
39
|
|
30
40
|
# The DOM class convention is to use the singular form of an object or class. Examples:
|
31
41
|
#
|
@@ -34,15 +44,16 @@
|
|
34
44
|
#
|
35
45
|
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:
|
36
46
|
#
|
37
|
-
# dom_class(post,
|
38
|
-
# dom_class(Person,
|
47
|
+
# dom_class(post, 'edit') # => "edit_post"
|
48
|
+
# dom_class(Person, 'edit') # => "edit_person"
|
39
49
|
dom_class: (record_or_class, prefix = "") ->
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
singular =
|
51
|
+
_.result(record_or_class, 'singular') ?
|
52
|
+
_.singularize _.string.underscored(
|
53
|
+
if _.isString(record_or_class)
|
54
|
+
record_or_class
|
55
|
+
else
|
56
|
+
@model_name_from_record_or_class(record_or_class) )
|
46
57
|
if prefix then "#{prefix}_#{singular}" else singular
|
47
58
|
|
48
59
|
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
|
@@ -56,11 +67,14 @@
|
|
56
67
|
# dom_id(Post.find(45), "edit") # => "edit_post_45"
|
57
68
|
# TODO sync with rorId and ror_id
|
58
69
|
dom_id: (record, prefix = "") ->
|
59
|
-
if record_id = @
|
70
|
+
if record_id = @_record_key_for_dom_id(record)
|
60
71
|
"#{@dom_class(record, prefix)}_#{record_id}"
|
61
72
|
else
|
62
73
|
@dom_class(record, prefix or "new")
|
63
74
|
|
64
|
-
|
65
|
-
|
66
|
-
|
75
|
+
|
76
|
+
|
77
|
+
# protected
|
78
|
+
|
79
|
+
_record_key_for_dom_id: (record) ->
|
80
|
+
record.id
|
@@ -11,7 +11,7 @@
|
|
11
11
|
textarea: "\n"
|
12
12
|
|
13
13
|
tag: (tag_name, options = {}, open = false, escape = true) ->
|
14
|
-
"<#{tag_name}#{@tag_options(options)}#{if open then '>' else ' />'}"
|
14
|
+
"<#{tag_name}#{@tag_options(options, escape)}#{if open then '>' else ' />'}"
|
15
15
|
|
16
16
|
content_tag: (name, content_or_options_with_block = null, options = null, escape = true, block = null) ->
|
17
17
|
if block = _.outcasts.blockGiven(arguments)
|
@@ -20,13 +20,17 @@
|
|
20
20
|
else
|
21
21
|
@content_tag_string(name, content_or_options_with_block, options, escape)
|
22
22
|
|
23
|
+
cdata_section: (content) ->
|
24
|
+
splitted = content.replace(/\]\]>/g, ']]]]><![CDATA[>')
|
25
|
+
"<![CDATA[#{splitted}]]>"
|
26
|
+
|
23
27
|
content_tag_string: (name, content = '', options = {}, escape = true) ->
|
24
|
-
content = _.
|
28
|
+
content = _.string.escapeHTML(content) if escape
|
25
29
|
"<#{name}#{@tag_options(options, escape)}>#{@PRE_CONTENT_STRINGS[name] ? ''}#{content}</#{name}>"
|
26
30
|
|
27
31
|
html_options_to_s: (html_options, escape = false, prefix = "") ->
|
28
32
|
deprecate 'html_options_to_s()', "tag_options()"
|
29
|
-
@tag_options
|
33
|
+
@tag_options arguments...
|
30
34
|
|
31
35
|
tag_options: (options, escape = true) ->
|
32
36
|
return "" if _.isEmpty(options)
|
@@ -1,17 +1,22 @@
|
|
1
1
|
#= require ./base
|
2
2
|
#= require ./tag
|
3
|
+
#= require ./javascript
|
4
|
+
|
5
|
+
__char_encode = (char) -> "%#{char.charCodeAt(0).toString(16)}"
|
6
|
+
escape_path = (str) -> str.replace(/[^*\-.0-9A-Z_a-z]/g, __char_encode).replace(/\+/g, '%20')
|
7
|
+
__string_encode = (str) -> _.map(str, (char) -> "&##{char.charCodeAt(0)};" ).join('')
|
3
8
|
|
4
9
|
@Ultimate.Helpers.Url =
|
5
10
|
|
6
11
|
url_for: (options = null) ->
|
7
12
|
if _.isString(options)
|
8
|
-
if options is
|
13
|
+
if options is 'back'
|
9
14
|
'javascript:history.back();'
|
10
15
|
else
|
11
16
|
options
|
12
17
|
else unless _.isEmpty(options)
|
13
18
|
url = _.result(options, 'url') ? ''
|
14
|
-
if
|
19
|
+
if $.isPlainObject(options)
|
15
20
|
options = _.clone(options)
|
16
21
|
delete options['url']
|
17
22
|
anchor = _.outcasts.delete(options, 'anchor')
|
@@ -26,8 +31,41 @@
|
|
26
31
|
options ||= {}
|
27
32
|
url = @url_for(options)
|
28
33
|
html_options = @_convert_options_to_data_attributes(options, html_options)
|
29
|
-
html_options[
|
30
|
-
|
34
|
+
html_options['href'] ||= url
|
35
|
+
if block
|
36
|
+
Ultimate.Helpers.Tag.content_tag('a', html_options, null, false, block)
|
37
|
+
else
|
38
|
+
Ultimate.Helpers.Tag.content_tag('a', name or url, html_options, false)
|
39
|
+
|
40
|
+
link_to_js: (name = null, html_options = null, block = null) ->
|
41
|
+
[options, name] = [name, null] if block = _.outcasts.blockGiven(arguments)
|
42
|
+
@link_to [name, options, html_options, block]...
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
mail_to: (email_address, name = null, html_options = {}) ->
|
47
|
+
email_address = _.string.escapeHTML(email_address)
|
48
|
+
encode = _.outcasts.delete(html_options, 'encode')
|
49
|
+
extras = _.compact _.map _.string.words('cc bcc body subject'), (item) ->
|
50
|
+
option = _.outcasts.delete(html_options, item)
|
51
|
+
if option?
|
52
|
+
"#{item}=#{escape_path(option)}"
|
53
|
+
extras = if _.isEmpty(extras) then '' else '?' + _.string.escapeHTML(extras.join('&'))
|
54
|
+
email_address_obfuscated = email_address
|
55
|
+
email_address_obfuscated = email_address_obfuscated.replace('@', _.outcasts.delete(html_options, 'replace_at')) if 'replace_at' of html_options
|
56
|
+
email_address_obfuscated = email_address_obfuscated.replace('.', _.outcasts.delete(html_options, 'replace_dot')) if 'replace_dot' of html_options
|
57
|
+
switch encode
|
58
|
+
when 'javascript'
|
59
|
+
html = @link_to(name or email_address_obfuscated, "mailto:#{email_address}#{extras}", html_options)
|
60
|
+
html = Ultimate.Helpers.Javascript.escape_javascript(html)
|
61
|
+
string = _.map("document.write('#{html}');", __char_encode).join('')
|
62
|
+
"<script>eval(decodeURIComponent('#{string}'))</script>"
|
63
|
+
when 'hex'
|
64
|
+
email_address_encoded = __string_encode(email_address_obfuscated)
|
65
|
+
string = __string_encode('mailto:') + _.map(email_address, (char) -> if /\w/.test(char) then __char_encode(char) else char).join('')
|
66
|
+
@link_to name or email_address_encoded, "#{string}#{extras}", html_options
|
67
|
+
else
|
68
|
+
@link_to name or email_address_obfuscated, "mailto:#{email_address}#{extras}", html_options
|
31
69
|
|
32
70
|
|
33
71
|
|
@@ -44,6 +82,23 @@
|
|
44
82
|
_.isObject(options) and _.outcasts.delete(options, 'remote')
|
45
83
|
|
46
84
|
_add_method_to_attributes: (html_options, method) ->
|
47
|
-
if _.isString(method) and method.toLowerCase() isnt
|
48
|
-
html_options[
|
49
|
-
html_options[
|
85
|
+
if _.isString(method) and method.toLowerCase() isnt 'get' and not /nofollow/.test(html_options['rel'])
|
86
|
+
html_options['rel'] = _.string.lstrip("#{html_options['rel']} nofollow")
|
87
|
+
html_options['data-method'] = method
|
88
|
+
|
89
|
+
_convert_boolean_attributes: (html_options, bool_attrs) ->
|
90
|
+
html_options[x] = x for x in bool_attrs when _.outcasts.delete(html_options, x)
|
91
|
+
html_options
|
92
|
+
|
93
|
+
__protect_against_forgery: false
|
94
|
+
__form_authenticity_token: 'secret'
|
95
|
+
__request_forgery_protection_token: 'form_token'
|
96
|
+
|
97
|
+
_token_tag: (token = @__form_authenticity_token) ->
|
98
|
+
if token isnt false and @__protect_against_forgery
|
99
|
+
Ultimate.Helpers.Tag.tag 'input', type: 'hidden', name: @__request_forgery_protection_token, value: token
|
100
|
+
else
|
101
|
+
''
|
102
|
+
|
103
|
+
_method_tag: (method) ->
|
104
|
+
Ultimate.Helpers.Tag.tag 'input', type: 'hidden', name: '_method', value: method
|