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.
Files changed (35) hide show
  1. data/Gemfile.lock +15 -15
  2. data/app/assets/javascripts/ultimate/backbone/lib/backbone.js +70 -56
  3. data/app/assets/javascripts/ultimate/backbone/model.js.coffee +2 -2
  4. data/app/assets/javascripts/ultimate/backbone/view.js.coffee +5 -4
  5. data/app/assets/javascripts/ultimate/backbone/views/typed-fields.js.coffee +1 -1
  6. data/app/assets/javascripts/ultimate/helpers/asset_tag.js.coffee +21 -19
  7. data/app/assets/javascripts/ultimate/helpers/form_options.js.coffee +65 -0
  8. data/app/assets/javascripts/ultimate/helpers/form_tag.js.coffee +177 -0
  9. data/app/assets/javascripts/ultimate/helpers/javascript.js.coffee +31 -0
  10. data/app/assets/javascripts/ultimate/helpers/record_tag.js.coffee +29 -15
  11. data/app/assets/javascripts/ultimate/helpers/tag.js.coffee +7 -3
  12. data/app/assets/javascripts/ultimate/helpers/url.js.coffee +62 -7
  13. data/app/assets/javascripts/ultimate/jquery-plugin-adapter.js.coffee +1 -0
  14. data/app/assets/javascripts/ultimate/jquery-plugin-class.js.coffee +35 -16
  15. data/app/assets/javascripts/ultimate/jquery.base.js.coffee +1 -1
  16. data/app/assets/javascripts/ultimate/underscore/underscore.js +292 -192
  17. data/app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee +27 -2
  18. data/app/assets/javascripts/ultimate/underscore/underscore.string.js +4 -4
  19. data/app/assets/stylesheets/polyfills/PIE.htc +81 -81
  20. data/app/assets/stylesheets/polyfills/boxsizing.htc +255 -54
  21. data/app/assets/stylesheets/ultimate/mixins/_vendors.scss +9 -0
  22. data/app/assets/stylesheets/ultimate/mixins/css3.scss +39 -28
  23. data/app/assets/stylesheets/ultimate/mixins/microstructures.scss +32 -6
  24. data/lib/ultimate/base/version.rb +1 -1
  25. data/test/javascripts/tests/helpers/asset_tag_test.js.coffee +1 -1
  26. data/test/javascripts/tests/helpers/form_options_test.js.coffee +96 -0
  27. data/test/javascripts/tests/helpers/form_tag_test.js.coffee +225 -0
  28. data/test/javascripts/tests/helpers/javascript_test.js.coffee +25 -0
  29. data/test/javascripts/tests/helpers/record_tag_test.js.coffee +5 -3
  30. data/test/javascripts/tests/helpers/tag_test.js.coffee +22 -17
  31. data/test/javascripts/tests/helpers/url_test.js.coffee +50 -6
  32. data/test/javascripts/tests/underscore/underscore.outcasts.test.js.coffee +9 -0
  33. metadata +8 -4
  34. data/app/assets/javascripts/ultimate/helpers/translation.js.coffee +0 -97
  35. 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: '&#x2713;', 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
- # ============= from ActionController::RecordIdentifier ===============
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, :edit) # => "edit_post"
38
- # dom_class(Person, :edit) # => "edit_person"
47
+ # dom_class(post, 'edit') # => "edit_post"
48
+ # dom_class(Person, 'edit') # => "edit_person"
39
49
  dom_class: (record_or_class, prefix = "") ->
40
- # TODO improve as in Ultimate.Backbone.Model
41
- if _.isString(record_or_class)
42
- singular = _.singularize(record_or_class)
43
- else unless singular = _.result(record_or_class, 'singular')
44
- if _.isString(record_or_class?.constructor?.name)
45
- singular = _.singularize(_.string.underscored(record_or_class.constructor.name))
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 = @sanitize_dom_id(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
- # Replaces characters that are invalid in HTML DOM ids with valid ones.
65
- sanitize_dom_id: (candidate_id) ->
66
- candidate_id # TODO implement conversion to valid DOM id values
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 = _.escape(content) if escape
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.apply(@, arguments)
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 "back"
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 _.isObject(options)
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["href"] ||= url
30
- Ultimate.Helpers.Tag.content_tag("a", name or url, html_options, false, block)
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 "get" and not /nofollow/.test(html_options["rel"])
48
- html_options["rel"] = _.string.lstrip("#{html_options["rel"]} nofollow")
49
- html_options["data-method"] = method
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