actionpack 3.2.19 → 4.0.0
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/CHANGELOG.md +850 -401
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -288
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +39 -37
- data/lib/abstract_controller/callbacks.rb +101 -82
- data/lib/abstract_controller/collector.rb +7 -3
- data/lib/abstract_controller/helpers.rb +25 -13
- data/lib/abstract_controller/layouts.rb +74 -74
- data/lib/abstract_controller/logger.rb +1 -2
- data/lib/abstract_controller/rendering.rb +30 -13
- data/lib/abstract_controller/translation.rb +16 -1
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller/view_paths.rb +1 -1
- data/lib/abstract_controller.rb +1 -8
- data/lib/action_controller/base.rb +46 -22
- data/lib/action_controller/caching/fragments.rb +23 -53
- data/lib/action_controller/caching.rb +46 -33
- data/lib/action_controller/deprecated/integration_test.rb +3 -0
- data/lib/action_controller/deprecated.rb +5 -1
- data/lib/action_controller/log_subscriber.rb +16 -8
- data/lib/action_controller/metal/conditional_get.rb +76 -32
- data/lib/action_controller/metal/data_streaming.rb +20 -26
- data/lib/action_controller/metal/exceptions.rb +19 -6
- data/lib/action_controller/metal/flash.rb +24 -9
- data/lib/action_controller/metal/force_ssl.rb +70 -12
- data/lib/action_controller/metal/head.rb +25 -4
- data/lib/action_controller/metal/helpers.rb +5 -9
- data/lib/action_controller/metal/hide_actions.rb +0 -1
- data/lib/action_controller/metal/http_authentication.rb +107 -83
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +2 -1
- data/lib/action_controller/metal/live.rb +175 -0
- data/lib/action_controller/metal/mime_responds.rb +161 -47
- data/lib/action_controller/metal/params_wrapper.rb +112 -74
- data/lib/action_controller/metal/rack_delegation.rb +9 -3
- data/lib/action_controller/metal/redirecting.rb +15 -20
- data/lib/action_controller/metal/renderers.rb +11 -9
- data/lib/action_controller/metal/rendering.rb +9 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
- data/lib/action_controller/metal/responder.rb +20 -19
- data/lib/action_controller/metal/streaming.rb +12 -18
- data/lib/action_controller/metal/strong_parameters.rb +520 -0
- data/lib/action_controller/metal/testing.rb +13 -18
- data/lib/action_controller/metal/url_for.rb +28 -25
- data/lib/action_controller/metal.rb +17 -32
- data/lib/action_controller/model_naming.rb +12 -0
- data/lib/action_controller/railtie.rb +33 -17
- data/lib/action_controller/railties/helpers.rb +22 -0
- data/lib/action_controller/record_identifier.rb +18 -72
- data/lib/action_controller/test_case.rb +251 -131
- data/lib/action_controller/vendor/html-scanner.rb +4 -19
- data/lib/action_controller.rb +15 -6
- data/lib/action_dispatch/http/cache.rb +63 -11
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +49 -17
- data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
- data/lib/action_dispatch/http/mime_type.rb +154 -100
- data/lib/action_dispatch/http/mime_types.rb +1 -1
- data/lib/action_dispatch/http/parameter_filter.rb +44 -46
- data/lib/action_dispatch/http/parameters.rb +28 -28
- data/lib/action_dispatch/http/rack_cache.rb +2 -3
- data/lib/action_dispatch/http/request.rb +64 -18
- data/lib/action_dispatch/http/response.rb +130 -35
- data/lib/action_dispatch/http/upload.rb +63 -20
- data/lib/action_dispatch/http/url.rb +98 -35
- data/lib/action_dispatch/journey/backwards.rb +5 -0
- data/lib/action_dispatch/journey/formatter.rb +146 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
- data/lib/action_dispatch/journey/nodes/node.rb +124 -0
- data/lib/action_dispatch/journey/parser.rb +206 -0
- data/lib/action_dispatch/journey/parser.y +47 -0
- data/lib/action_dispatch/journey/parser_extras.rb +23 -0
- data/lib/action_dispatch/journey/path/pattern.rb +196 -0
- data/lib/action_dispatch/journey/route.rb +124 -0
- data/lib/action_dispatch/journey/router/strexp.rb +24 -0
- data/lib/action_dispatch/journey/router/utils.rb +54 -0
- data/lib/action_dispatch/journey/router.rb +166 -0
- data/lib/action_dispatch/journey/routes.rb +75 -0
- data/lib/action_dispatch/journey/scanner.rb +61 -0
- data/lib/action_dispatch/journey/visitors.rb +197 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +5 -0
- data/lib/action_dispatch/middleware/callbacks.rb +9 -4
- data/lib/action_dispatch/middleware/cookies.rb +259 -114
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
- data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
- data/lib/action_dispatch/middleware/flash.rb +58 -58
- data/lib/action_dispatch/middleware/params_parser.rb +14 -29
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
- data/lib/action_dispatch/middleware/reloader.rb +6 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
- data/lib/action_dispatch/middleware/request_id.rb +2 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
- data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
- data/lib/action_dispatch/middleware/ssl.rb +70 -0
- data/lib/action_dispatch/middleware/stack.rb +6 -1
- data/lib/action_dispatch/middleware/static.rb +2 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
- data/lib/action_dispatch/railtie.rb +16 -6
- data/lib/action_dispatch/request/session.rb +181 -0
- data/lib/action_dispatch/routing/inspector.rb +240 -0
- data/lib/action_dispatch/routing/mapper.rb +540 -291
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
- data/lib/action_dispatch/routing/redirection.rb +46 -29
- data/lib/action_dispatch/routing/route_set.rb +207 -164
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
- data/lib/action_dispatch/routing/url_for.rb +48 -33
- data/lib/action_dispatch/routing.rb +48 -83
- data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
- data/lib/action_dispatch/testing/assertions/response.rb +32 -40
- data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
- data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
- data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
- data/lib/action_dispatch/testing/integration.rb +65 -51
- data/lib/action_dispatch/testing/test_process.rb +9 -6
- data/lib/action_dispatch/testing/test_request.rb +7 -3
- data/lib/action_dispatch.rb +21 -15
- data/lib/action_pack/version.rb +7 -6
- data/lib/action_pack.rb +1 -1
- data/lib/action_view/base.rb +15 -34
- data/lib/action_view/buffers.rb +7 -1
- data/lib/action_view/context.rb +4 -4
- data/lib/action_view/dependency_tracker.rb +93 -0
- data/lib/action_view/digestor.rb +85 -0
- data/lib/action_view/flows.rb +1 -4
- data/lib/action_view/helpers/active_model_helper.rb +3 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
- data/lib/action_view/helpers/asset_url_helper.rb +355 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
- data/lib/action_view/helpers/cache_helper.rb +150 -18
- data/lib/action_view/helpers/capture_helper.rb +44 -31
- data/lib/action_view/helpers/csrf_helper.rb +0 -2
- data/lib/action_view/helpers/date_helper.rb +269 -248
- data/lib/action_view/helpers/debug_helper.rb +10 -11
- data/lib/action_view/helpers/form_helper.rb +931 -537
- data/lib/action_view/helpers/form_options_helper.rb +341 -166
- data/lib/action_view/helpers/form_tag_helper.rb +190 -90
- data/lib/action_view/helpers/javascript_helper.rb +23 -16
- data/lib/action_view/helpers/number_helper.rb +148 -329
- data/lib/action_view/helpers/output_safety_helper.rb +3 -3
- data/lib/action_view/helpers/record_tag_helper.rb +17 -22
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +3 -6
- data/lib/action_view/helpers/tag_helper.rb +46 -33
- data/lib/action_view/helpers/tags/base.rb +147 -0
- data/lib/action_view/helpers/tags/check_box.rb +64 -0
- data/lib/action_view/helpers/tags/checkable.rb +16 -0
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
- data/lib/action_view/helpers/tags/collection_select.rb +28 -0
- data/lib/action_view/helpers/tags/color_field.rb +25 -0
- data/lib/action_view/helpers/tags/date_field.rb +13 -0
- data/lib/action_view/helpers/tags/date_select.rb +72 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
- data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
- data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
- data/lib/action_view/helpers/tags/email_field.rb +8 -0
- data/lib/action_view/helpers/tags/file_field.rb +8 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
- data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
- data/lib/action_view/helpers/tags/label.rb +65 -0
- data/lib/action_view/helpers/tags/month_field.rb +13 -0
- data/lib/action_view/helpers/tags/number_field.rb +18 -0
- data/lib/action_view/helpers/tags/password_field.rb +12 -0
- data/lib/action_view/helpers/tags/radio_button.rb +31 -0
- data/lib/action_view/helpers/tags/range_field.rb +8 -0
- data/lib/action_view/helpers/tags/search_field.rb +24 -0
- data/lib/action_view/helpers/tags/select.rb +40 -0
- data/lib/action_view/helpers/tags/tel_field.rb +8 -0
- data/lib/action_view/helpers/tags/text_area.rb +18 -0
- data/lib/action_view/helpers/tags/text_field.rb +29 -0
- data/lib/action_view/helpers/tags/time_field.rb +13 -0
- data/lib/action_view/helpers/tags/time_select.rb +8 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
- data/lib/action_view/helpers/tags/url_field.rb +8 -0
- data/lib/action_view/helpers/tags/week_field.rb +13 -0
- data/lib/action_view/helpers/tags.rb +39 -0
- data/lib/action_view/helpers/text_helper.rb +130 -114
- data/lib/action_view/helpers/translation_helper.rb +32 -16
- data/lib/action_view/helpers/url_helper.rb +211 -270
- data/lib/action_view/helpers.rb +2 -4
- data/lib/action_view/locale/en.yml +1 -105
- data/lib/action_view/log_subscriber.rb +6 -4
- data/lib/action_view/lookup_context.rb +15 -28
- data/lib/action_view/model_naming.rb +12 -0
- data/lib/action_view/path_set.rb +8 -20
- data/lib/action_view/railtie.rb +6 -22
- data/lib/action_view/record_identifier.rb +84 -0
- data/lib/action_view/renderer/abstract_renderer.rb +25 -19
- data/lib/action_view/renderer/partial_renderer.rb +158 -81
- data/lib/action_view/renderer/renderer.rb +8 -12
- data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
- data/lib/action_view/renderer/template_renderer.rb +12 -10
- data/lib/action_view/routing_url_for.rb +107 -0
- data/lib/action_view/template/error.rb +22 -12
- data/lib/action_view/template/handlers/builder.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +40 -19
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/handlers.rb +12 -9
- data/lib/action_view/template/resolver.rb +107 -53
- data/lib/action_view/template/text.rb +12 -8
- data/lib/action_view/template/types.rb +57 -0
- data/lib/action_view/template.rb +25 -23
- data/lib/action_view/test_case.rb +67 -42
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
- data/lib/action_view/vendor/html-scanner.rb +20 -0
- data/lib/action_view.rb +17 -8
- metadata +184 -214
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
|
2
1
|
require 'active_support/core_ext/string/filters'
|
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
|
3
3
|
|
|
4
4
|
module ActionView
|
|
5
5
|
# = Action View Text Helpers
|
|
@@ -36,7 +36,6 @@ module ActionView
|
|
|
36
36
|
# do not operate as expected in an eRuby code block. If you absolutely must
|
|
37
37
|
# output text within a non-output code block (i.e., <% %>), you can use the concat method.
|
|
38
38
|
#
|
|
39
|
-
# ==== Examples
|
|
40
39
|
# <%
|
|
41
40
|
# concat "hello"
|
|
42
41
|
# # is the equivalent of <%= "hello" %>
|
|
@@ -44,7 +43,7 @@ module ActionView
|
|
|
44
43
|
# if logged_in
|
|
45
44
|
# concat "Logged in!"
|
|
46
45
|
# else
|
|
47
|
-
# concat link_to('login', :
|
|
46
|
+
# concat link_to('login', action: :login)
|
|
48
47
|
# end
|
|
49
48
|
# # will either display "Logged in!" or a login link
|
|
50
49
|
# %>
|
|
@@ -62,128 +61,121 @@ module ActionView
|
|
|
62
61
|
#
|
|
63
62
|
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
|
|
64
63
|
#
|
|
65
|
-
#
|
|
66
|
-
# used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
|
|
67
|
-
# or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
|
|
64
|
+
# Pass a block if you want to show extra content when the text is truncated.
|
|
68
65
|
#
|
|
69
|
-
#
|
|
66
|
+
# The result is marked as HTML-safe, but it is escaped by default, unless <tt>:escape</tt> is
|
|
67
|
+
# +false+. Care should be taken if +text+ contains HTML tags or entities, because truncation
|
|
68
|
+
# may produce invalid HTML (such as unbalanced or incomplete tags).
|
|
70
69
|
#
|
|
71
70
|
# truncate("Once upon a time in a world far far away")
|
|
72
71
|
# # => "Once upon a time in a world..."
|
|
73
72
|
#
|
|
74
|
-
# truncate("Once upon a time in a world far far away", :
|
|
73
|
+
# truncate("Once upon a time in a world far far away", length: 17)
|
|
75
74
|
# # => "Once upon a ti..."
|
|
76
75
|
#
|
|
77
|
-
# truncate("Once upon a time in a world far far away", :
|
|
76
|
+
# truncate("Once upon a time in a world far far away", length: 17, separator: ' ')
|
|
78
77
|
# # => "Once upon a..."
|
|
79
78
|
#
|
|
80
|
-
# truncate("And they found that many people were sleeping better.", :
|
|
79
|
+
# truncate("And they found that many people were sleeping better.", length: 25, omission: '... (continued)')
|
|
81
80
|
# # => "And they f... (continued)"
|
|
82
81
|
#
|
|
83
82
|
# truncate("<p>Once upon a time in a world far far away</p>")
|
|
84
83
|
# # => "<p>Once upon a time in a wo..."
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
#
|
|
85
|
+
# truncate("Once upon a time in a world far far away") { link_to "Continue", "#" }
|
|
86
|
+
# # => "Once upon a time in a wo...<a href="#">Continue</a>"
|
|
87
|
+
def truncate(text, options = {}, &block)
|
|
88
|
+
if text
|
|
89
|
+
length = options.fetch(:length, 30)
|
|
90
|
+
|
|
91
|
+
content = text.truncate(length, options)
|
|
92
|
+
content = options[:escape] == false ? content.html_safe : ERB::Util.html_escape(content)
|
|
93
|
+
content << capture(&block) if block_given? && text.length > length
|
|
94
|
+
content
|
|
95
|
+
end
|
|
88
96
|
end
|
|
89
97
|
|
|
90
98
|
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
|
|
91
99
|
# a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt>
|
|
92
|
-
# as a single-quoted string with
|
|
93
|
-
# '<
|
|
100
|
+
# as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to
|
|
101
|
+
# '<mark>\1</mark>')
|
|
94
102
|
#
|
|
95
|
-
# ==== Examples
|
|
96
103
|
# highlight('You searched for: rails', 'rails')
|
|
97
|
-
# # => You searched for: <
|
|
104
|
+
# # => You searched for: <mark>rails</mark>
|
|
98
105
|
#
|
|
99
106
|
# highlight('You searched for: ruby, rails, dhh', 'actionpack')
|
|
100
107
|
# # => You searched for: ruby, rails, dhh
|
|
101
108
|
#
|
|
102
|
-
# highlight('You searched for: rails', ['for', 'rails'], :
|
|
109
|
+
# highlight('You searched for: rails', ['for', 'rails'], highlighter: '<em>\1</em>')
|
|
103
110
|
# # => You searched <em>for</em>: <em>rails</em>
|
|
104
111
|
#
|
|
105
|
-
# highlight('You searched for: rails', 'rails', :
|
|
112
|
+
# highlight('You searched for: rails', 'rails', highlighter: '<a href="search?q=\1">\1</a>')
|
|
106
113
|
# # => You searched for: <a href="search?q=rails">rails</a>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# +highlighter+ as its optional third parameter:
|
|
110
|
-
# highlight('You searched for: rails', 'rails', '<a href="search?q=\1">\1</a>') # => You searched for: <a href="search?q=rails">rails</a>
|
|
111
|
-
def highlight(text, phrases, *args)
|
|
112
|
-
options = args.extract_options!
|
|
113
|
-
unless args.empty?
|
|
114
|
-
ActiveSupport::Deprecation.warn "Calling highlight with a highlighter as an argument is deprecated. " \
|
|
115
|
-
"Please call with :highlighter => '#{args[0]}' instead.", caller
|
|
114
|
+
def highlight(text, phrases, options = {})
|
|
115
|
+
text = sanitize(text) if options.fetch(:sanitize, true)
|
|
116
116
|
|
|
117
|
-
options[:highlighter] = args[0] || '<strong class="highlight">\1</strong>'
|
|
118
|
-
end
|
|
119
|
-
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
|
|
120
|
-
|
|
121
|
-
text = sanitize(text) unless options[:sanitize] == false
|
|
122
117
|
if text.blank? || phrases.blank?
|
|
123
118
|
text
|
|
124
119
|
else
|
|
120
|
+
highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
|
|
125
121
|
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
|
|
126
|
-
text.gsub(/(#{match})(?![^<]*?>)/i,
|
|
122
|
+
text.gsub(/(#{match})(?![^<]*?>)/i, highlighter)
|
|
127
123
|
end.html_safe
|
|
128
124
|
end
|
|
129
125
|
|
|
130
126
|
# Extracts an excerpt from +text+ that matches the first instance of +phrase+.
|
|
131
127
|
# The <tt>:radius</tt> option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
|
|
132
128
|
# defined in <tt>:radius</tt> (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
|
|
133
|
-
# then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly.
|
|
134
|
-
# will be stripped in any case. If the +phrase+
|
|
129
|
+
# then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. Use the
|
|
130
|
+
# <tt>:separator</tt> option to choose the delimitation. The resulting string will be stripped in any case. If the +phrase+
|
|
131
|
+
# isn't found, nil is returned.
|
|
135
132
|
#
|
|
136
|
-
#
|
|
137
|
-
# excerpt('This is an example', 'an', :radius => 5)
|
|
133
|
+
# excerpt('This is an example', 'an', radius: 5)
|
|
138
134
|
# # => ...s is an exam...
|
|
139
135
|
#
|
|
140
|
-
# excerpt('This is an example', 'is', :
|
|
136
|
+
# excerpt('This is an example', 'is', radius: 5)
|
|
141
137
|
# # => This is a...
|
|
142
138
|
#
|
|
143
139
|
# excerpt('This is an example', 'is')
|
|
144
140
|
# # => This is an example
|
|
145
141
|
#
|
|
146
|
-
# excerpt('This next thing is an example', 'ex', :
|
|
142
|
+
# excerpt('This next thing is an example', 'ex', radius: 2)
|
|
147
143
|
# # => ...next...
|
|
148
144
|
#
|
|
149
|
-
# excerpt('This is also an example', 'an', :
|
|
145
|
+
# excerpt('This is also an example', 'an', radius: 8, omission: '<chop> ')
|
|
150
146
|
# # => <chop> is also an example
|
|
151
147
|
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
|
|
155
|
-
# excerpt('This is an example', 'an', 5) # => ...s is an exam...
|
|
156
|
-
# excerpt('This is also an example', 'an', 8, '<chop> ') # => <chop> is also an example
|
|
157
|
-
def excerpt(text, phrase, *args)
|
|
148
|
+
# excerpt('This is a very beautiful morning', 'very', separator: ' ', radius: 1)
|
|
149
|
+
# # => ...a very beautiful...
|
|
150
|
+
def excerpt(text, phrase, options = {})
|
|
158
151
|
return unless text && phrase
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"Please call with :radius => #{args[0]}#{", :omission => '#{args[1]}'" if args[1]} instead.", caller
|
|
153
|
+
separator = options.fetch(:separator, "")
|
|
154
|
+
phrase = Regexp.escape(phrase)
|
|
155
|
+
regex = /#{phrase}/i
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
end
|
|
168
|
-
options.reverse_merge!(:radius => 100, :omission => "...")
|
|
157
|
+
return unless matches = text.match(regex)
|
|
158
|
+
phrase = matches[0]
|
|
169
159
|
|
|
170
|
-
|
|
171
|
-
|
|
160
|
+
text.split(separator).each do |value|
|
|
161
|
+
if value.match(regex)
|
|
162
|
+
regex = phrase = value
|
|
163
|
+
break
|
|
164
|
+
end
|
|
165
|
+
end
|
|
172
166
|
|
|
173
|
-
|
|
174
|
-
end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
|
|
167
|
+
first_part, second_part = text.split(regex, 2)
|
|
175
168
|
|
|
176
|
-
prefix
|
|
177
|
-
postfix =
|
|
169
|
+
prefix, first_part = cut_excerpt_part(:first, first_part, separator, options)
|
|
170
|
+
postfix, second_part = cut_excerpt_part(:second, second_part, separator, options)
|
|
178
171
|
|
|
179
|
-
prefix +
|
|
172
|
+
prefix + (first_part + separator + phrase + separator + second_part).strip + postfix
|
|
180
173
|
end
|
|
181
174
|
|
|
182
175
|
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
|
183
176
|
# +plural+ is supplied, it will use that when count is > 1, otherwise
|
|
184
|
-
# it will use the Inflector to determine the plural form
|
|
177
|
+
# it will use the Inflector to determine the plural form.
|
|
185
178
|
#
|
|
186
|
-
# ==== Examples
|
|
187
179
|
# pluralize(1, 'person')
|
|
188
180
|
# # => 1 person
|
|
189
181
|
#
|
|
@@ -196,42 +188,35 @@ module ActionView
|
|
|
196
188
|
# pluralize(0, 'person')
|
|
197
189
|
# # => 0 people
|
|
198
190
|
def pluralize(count, singular, plural = nil)
|
|
199
|
-
|
|
191
|
+
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
|
192
|
+
singular
|
|
193
|
+
else
|
|
194
|
+
plural || singular.pluralize
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
"#{count || 0} #{word}"
|
|
200
198
|
end
|
|
201
199
|
|
|
202
200
|
# Wraps the +text+ into lines no longer than +line_width+ width. This method
|
|
203
201
|
# breaks on the first whitespace character that does not exceed +line_width+
|
|
204
202
|
# (which is 80 by default).
|
|
205
203
|
#
|
|
206
|
-
# ==== Examples
|
|
207
|
-
#
|
|
208
204
|
# word_wrap('Once upon a time')
|
|
209
205
|
# # => Once upon a time
|
|
210
206
|
#
|
|
211
207
|
# word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
|
|
212
|
-
# # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\
|
|
208
|
+
# # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...
|
|
213
209
|
#
|
|
214
|
-
# word_wrap('Once upon a time', :
|
|
215
|
-
# # => Once
|
|
210
|
+
# word_wrap('Once upon a time', line_width: 8)
|
|
211
|
+
# # => Once\nupon a\ntime
|
|
216
212
|
#
|
|
217
|
-
# word_wrap('Once upon a time', :
|
|
213
|
+
# word_wrap('Once upon a time', line_width: 1)
|
|
218
214
|
# # => Once\nupon\na\ntime
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# +line_width+ as its optional second parameter:
|
|
222
|
-
# word_wrap('Once upon a time', 8) # => Once upon\na time
|
|
223
|
-
def word_wrap(text, *args)
|
|
224
|
-
options = args.extract_options!
|
|
225
|
-
unless args.blank?
|
|
226
|
-
ActiveSupport::Deprecation.warn "Calling word_wrap with line_width as an argument is deprecated. " \
|
|
227
|
-
"Please call with :line_width => #{args[0]} instead.", caller
|
|
228
|
-
|
|
229
|
-
options[:line_width] = args[0] || 80
|
|
230
|
-
end
|
|
231
|
-
options.reverse_merge!(:line_width => 80)
|
|
215
|
+
def word_wrap(text, options = {})
|
|
216
|
+
line_width = options.fetch(:line_width, 80)
|
|
232
217
|
|
|
233
218
|
text.split("\n").collect do |line|
|
|
234
|
-
line.length >
|
|
219
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
|
|
235
220
|
end * "\n"
|
|
236
221
|
end
|
|
237
222
|
|
|
@@ -246,6 +231,7 @@ module ActionView
|
|
|
246
231
|
#
|
|
247
232
|
# ==== Options
|
|
248
233
|
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
|
|
234
|
+
# * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt>
|
|
249
235
|
#
|
|
250
236
|
# ==== Examples
|
|
251
237
|
# my_text = "Here is some basic text...\n...with a line break."
|
|
@@ -253,27 +239,35 @@ module ActionView
|
|
|
253
239
|
# simple_format(my_text)
|
|
254
240
|
# # => "<p>Here is some basic text...\n<br />...with a line break.</p>"
|
|
255
241
|
#
|
|
242
|
+
# simple_format(my_text, {}, wrapper_tag: "div")
|
|
243
|
+
# # => "<div>Here is some basic text...\n<br />...with a line break.</div>"
|
|
244
|
+
#
|
|
256
245
|
# more_text = "We want to put a paragraph...\n\n...right there."
|
|
257
246
|
#
|
|
258
247
|
# simple_format(more_text)
|
|
259
248
|
# # => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"
|
|
260
249
|
#
|
|
261
|
-
# simple_format("Look ma! A class!", :
|
|
250
|
+
# simple_format("Look ma! A class!", class: 'description')
|
|
262
251
|
# # => "<p class='description'>Look ma! A class!</p>"
|
|
263
252
|
#
|
|
264
|
-
# simple_format("<
|
|
265
|
-
# # => "<p
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
text
|
|
273
|
-
text
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
253
|
+
# simple_format("<blink>Unblinkable.</blink>")
|
|
254
|
+
# # => "<p>Unblinkable.</p>"
|
|
255
|
+
#
|
|
256
|
+
# simple_format("<blink>Blinkable!</blink> It's true.", {}, sanitize: false)
|
|
257
|
+
# # => "<p><blink>Blinkable!</span> It's true.</p>"
|
|
258
|
+
def simple_format(text, html_options = {}, options = {})
|
|
259
|
+
wrapper_tag = options.fetch(:wrapper_tag, :p)
|
|
260
|
+
|
|
261
|
+
text = sanitize(text) if options.fetch(:sanitize, true)
|
|
262
|
+
paragraphs = split_paragraphs(text)
|
|
263
|
+
|
|
264
|
+
if paragraphs.empty?
|
|
265
|
+
content_tag(wrapper_tag, nil, html_options)
|
|
266
|
+
else
|
|
267
|
+
paragraphs.map { |paragraph|
|
|
268
|
+
content_tag(wrapper_tag, paragraph, html_options, options[:sanitize])
|
|
269
|
+
}.join("\n\n").html_safe
|
|
270
|
+
end
|
|
277
271
|
end
|
|
278
272
|
|
|
279
273
|
# Creates a Cycle object whose _to_s_ method cycles through elements of an
|
|
@@ -285,7 +279,6 @@ module ActionView
|
|
|
285
279
|
# and passing the name of the cycle. The current cycle string can be obtained
|
|
286
280
|
# anytime using the current_cycle method.
|
|
287
281
|
#
|
|
288
|
-
# ==== Examples
|
|
289
282
|
# # Alternate CSS classes for even and odd numbers...
|
|
290
283
|
# @items = [1,2,3,4]
|
|
291
284
|
# <table>
|
|
@@ -298,15 +291,15 @@ module ActionView
|
|
|
298
291
|
#
|
|
299
292
|
#
|
|
300
293
|
# # Cycle CSS classes for rows, and text colors for values within each row
|
|
301
|
-
# @items = x = [{:
|
|
302
|
-
# {:
|
|
303
|
-
# {:
|
|
294
|
+
# @items = x = [{first: 'Robert', middle: 'Daniel', last: 'James'},
|
|
295
|
+
# {first: 'Emily', middle: 'Shannon', maiden: 'Pike', last: 'Hicks'},
|
|
296
|
+
# {first: 'June', middle: 'Dae', last: 'Jones'}]
|
|
304
297
|
# <% @items.each do |item| %>
|
|
305
|
-
# <tr class="<%= cycle("odd", "even", :
|
|
298
|
+
# <tr class="<%= cycle("odd", "even", name: "row_class") -%>">
|
|
306
299
|
# <td>
|
|
307
300
|
# <% item.values.each do |value| %>
|
|
308
301
|
# <%# Create a named cycle "colors" %>
|
|
309
|
-
# <span style="color:<%= cycle("red", "green", "blue", :
|
|
302
|
+
# <span style="color:<%= cycle("red", "green", "blue", name: "colors") -%>">
|
|
310
303
|
# <%= value %>
|
|
311
304
|
# </span>
|
|
312
305
|
# <% end %>
|
|
@@ -315,12 +308,9 @@ module ActionView
|
|
|
315
308
|
# </tr>
|
|
316
309
|
# <% end %>
|
|
317
310
|
def cycle(first_value, *values)
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
else
|
|
322
|
-
name = "default"
|
|
323
|
-
end
|
|
311
|
+
options = values.extract_options!
|
|
312
|
+
name = options.fetch(:name, 'default')
|
|
313
|
+
|
|
324
314
|
values.unshift(first_value)
|
|
325
315
|
|
|
326
316
|
cycle = get_cycle(name)
|
|
@@ -334,7 +324,6 @@ module ActionView
|
|
|
334
324
|
# for complex table highlighting or any other design need which requires
|
|
335
325
|
# the current cycle string in more than one place.
|
|
336
326
|
#
|
|
337
|
-
# ==== Example
|
|
338
327
|
# # Alternate background colors
|
|
339
328
|
# @items = [1,2,3,4]
|
|
340
329
|
# <% @items.each do |item| %>
|
|
@@ -350,14 +339,13 @@ module ActionView
|
|
|
350
339
|
# Resets a cycle so that it starts from the first element the next time
|
|
351
340
|
# it is called. Pass in +name+ to reset a named cycle.
|
|
352
341
|
#
|
|
353
|
-
# ==== Example
|
|
354
342
|
# # Alternate CSS classes for even and odd numbers...
|
|
355
343
|
# @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
|
|
356
344
|
# <table>
|
|
357
345
|
# <% @items.each do |item| %>
|
|
358
346
|
# <tr class="<%= cycle("even", "odd") -%>">
|
|
359
347
|
# <% item.each do |value| %>
|
|
360
|
-
# <span style="color:<%= cycle("#333", "#666", "#999", :
|
|
348
|
+
# <span style="color:<%= cycle("#333", "#666", "#999", name: "colors") -%>">
|
|
361
349
|
# <%= value %>
|
|
362
350
|
# </span>
|
|
363
351
|
# <% end %>
|
|
@@ -421,6 +409,34 @@ module ActionView
|
|
|
421
409
|
@_cycles = Hash.new unless defined?(@_cycles)
|
|
422
410
|
@_cycles[name] = cycle_object
|
|
423
411
|
end
|
|
412
|
+
|
|
413
|
+
def split_paragraphs(text)
|
|
414
|
+
return [] if text.blank?
|
|
415
|
+
|
|
416
|
+
text.to_str.gsub(/\r\n?/, "\n").split(/\n\n+/).map! do |t|
|
|
417
|
+
t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def cut_excerpt_part(part_position, part, separator, options)
|
|
422
|
+
return "", "" unless part
|
|
423
|
+
|
|
424
|
+
radius = options.fetch(:radius, 100)
|
|
425
|
+
omission = options.fetch(:omission, "...")
|
|
426
|
+
|
|
427
|
+
part = part.split(separator)
|
|
428
|
+
part.delete("")
|
|
429
|
+
affix = part.size > radius ? omission : ""
|
|
430
|
+
|
|
431
|
+
part = if part_position == :first
|
|
432
|
+
drop_index = [part.length - radius, 0].max
|
|
433
|
+
part.drop(drop_index)
|
|
434
|
+
else
|
|
435
|
+
part.first(radius)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
return affix, part.join(separator)
|
|
439
|
+
end
|
|
424
440
|
end
|
|
425
441
|
end
|
|
426
442
|
end
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
require 'action_view/helpers/tag_helper'
|
|
2
2
|
require 'i18n/exceptions'
|
|
3
3
|
|
|
4
|
+
module I18n
|
|
5
|
+
class ExceptionHandler
|
|
6
|
+
include Module.new {
|
|
7
|
+
def call(exception, locale, key, options)
|
|
8
|
+
exception.is_a?(MissingTranslation) && options[:rescue_format] == :html ? super.html_safe : super
|
|
9
|
+
end
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
4
14
|
module ActionView
|
|
5
15
|
# = Action View Translation Helpers
|
|
6
16
|
module Helpers
|
|
7
17
|
module TranslationHelper
|
|
8
18
|
# Delegates to <tt>I18n#translate</tt> but also performs three additional functions.
|
|
9
19
|
#
|
|
10
|
-
# First, it
|
|
11
|
-
# into inline spans that
|
|
20
|
+
# First, it'll pass the <tt>rescue_format: :html</tt> option to I18n so that any
|
|
21
|
+
# thrown +MissingTranslation+ messages will be turned into inline spans that
|
|
12
22
|
#
|
|
13
23
|
# * have a "translation-missing" class set,
|
|
14
24
|
# * contain the missing key as a title attribute and
|
|
@@ -34,15 +44,8 @@ module ActionView
|
|
|
34
44
|
# naming convention helps to identify translations that include HTML tags so that
|
|
35
45
|
# you know what kind of output to expect when you call translate in a template.
|
|
36
46
|
def translate(key, options = {})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if options.key?(:raise) || options.key?(:rescue_format)
|
|
40
|
-
raise_error = options[:raise] || options[:rescue_format]
|
|
41
|
-
else
|
|
42
|
-
raise_error = false
|
|
43
|
-
options[:raise] = true
|
|
44
|
-
end
|
|
45
|
-
|
|
47
|
+
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
|
|
48
|
+
options[:default] = wrap_translate_defaults(options[:default]) if options[:default]
|
|
46
49
|
if html_safe_translation_key?(key)
|
|
47
50
|
html_safe_options = options.dup
|
|
48
51
|
options.except(*I18n::RESERVED_KEYS).each do |name, value|
|
|
@@ -56,15 +59,13 @@ module ActionView
|
|
|
56
59
|
else
|
|
57
60
|
I18n.translate(scope_key_by_partial(key), options)
|
|
58
61
|
end
|
|
59
|
-
rescue I18n::MissingTranslationData => e
|
|
60
|
-
raise e if raise_error
|
|
61
|
-
|
|
62
|
-
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
|
63
|
-
content_tag('span', keys.last.to_s.titleize, :class => 'translation_missing', :title => "translation missing: #{keys.join('.')}")
|
|
64
62
|
end
|
|
65
63
|
alias :t :translate
|
|
66
64
|
|
|
67
65
|
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
|
|
66
|
+
#
|
|
67
|
+
# See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
|
|
68
|
+
# for more information.
|
|
68
69
|
def localize(*args)
|
|
69
70
|
I18n.localize(*args)
|
|
70
71
|
end
|
|
@@ -86,6 +87,21 @@ module ActionView
|
|
|
86
87
|
def html_safe_translation_key?(key)
|
|
87
88
|
key.to_s =~ /(\b|_|\.)html$/
|
|
88
89
|
end
|
|
90
|
+
|
|
91
|
+
def wrap_translate_defaults(defaults)
|
|
92
|
+
new_defaults = []
|
|
93
|
+
defaults = Array(defaults)
|
|
94
|
+
while key = defaults.shift
|
|
95
|
+
if key.is_a?(Symbol)
|
|
96
|
+
new_defaults << lambda { |_, options| translate key, options.merge(:default => defaults) }
|
|
97
|
+
break
|
|
98
|
+
else
|
|
99
|
+
new_defaults << key
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
new_defaults
|
|
104
|
+
end
|
|
89
105
|
end
|
|
90
106
|
end
|
|
91
107
|
end
|