actionpack 3.2.22.5 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +641 -418
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -288
- data/lib/abstract_controller.rb +1 -8
- 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 +23 -11
- data/lib/abstract_controller/layouts.rb +68 -73
- data/lib/abstract_controller/logger.rb +1 -2
- data/lib/abstract_controller/rendering.rb +22 -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/action_controller.rb +15 -6
- data/lib/action_controller/base.rb +46 -22
- data/lib/action_controller/caching.rb +46 -33
- data/lib/action_controller/caching/fragments.rb +23 -53
- data/lib/action_controller/deprecated.rb +5 -1
- data/lib/action_controller/deprecated/integration_test.rb +3 -0
- data/lib/action_controller/log_subscriber.rb +11 -8
- data/lib/action_controller/metal.rb +16 -30
- 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 +32 -9
- data/lib/action_controller/metal/head.rb +25 -4
- data/lib/action_controller/metal/helpers.rb +6 -9
- data/lib/action_controller/metal/hide_actions.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +105 -87
- 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 +141 -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 +8 -0
- 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 +516 -0
- data/lib/action_controller/metal/testing.rb +13 -18
- data/lib/action_controller/metal/url_for.rb +27 -25
- 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 +215 -123
- data/lib/action_controller/vendor/html-scanner.rb +4 -19
- data/lib/action_dispatch.rb +27 -19
- 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 +27 -19
- data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
- data/lib/action_dispatch/http/mime_type.rb +145 -113
- 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 +12 -5
- data/lib/action_dispatch/http/rack_cache.rb +2 -3
- data/lib/action_dispatch/http/request.rb +49 -18
- data/lib/action_dispatch/http/response.rb +129 -35
- data/lib/action_dispatch/http/upload.rb +60 -17
- data/lib/action_dispatch/http/url.rb +53 -31
- data/lib/action_dispatch/journey.rb +5 -0
- 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 +116 -0
- data/lib/action_dispatch/journey/router.rb +164 -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/routes.rb +75 -0
- data/lib/action_dispatch/journey/scanner.rb +61 -0
- data/lib/action_dispatch/journey/visitors.rb +189 -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/middleware/callbacks.rb +9 -4
- data/lib/action_dispatch/middleware/cookies.rb +168 -57
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
- data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -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 +31 -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/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
- 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 +5 -24
- 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 +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -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.rb +41 -40
- data/lib/action_dispatch/routing/inspector.rb +240 -0
- data/lib/action_dispatch/routing/mapper.rb +501 -273
- 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 +203 -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/testing/assertions/dom.rb +3 -13
- data/lib/action_dispatch/testing/assertions/response.rb +32 -40
- data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
- data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
- data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
- data/lib/action_dispatch/testing/integration.rb +41 -22
- data/lib/action_dispatch/testing/test_process.rb +9 -6
- data/lib/action_dispatch/testing/test_request.rb +7 -3
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +4 -4
- data/lib/action_view.rb +17 -8
- data/lib/action_view/base.rb +15 -34
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +4 -4
- data/lib/action_view/dependency_tracker.rb +91 -0
- data/lib/action_view/digestor.rb +85 -0
- data/lib/action_view/flows.rb +1 -4
- data/lib/action_view/helpers.rb +2 -4
- data/lib/action_view/helpers/active_model_helper.rb +3 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
- data/lib/action_view/helpers/asset_url_helper.rb +354 -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 +42 -29
- data/lib/action_view/helpers/csrf_helper.rb +0 -2
- data/lib/action_view/helpers/date_helper.rb +268 -247
- data/lib/action_view/helpers/debug_helper.rb +10 -11
- data/lib/action_view/helpers/form_helper.rb +904 -547
- data/lib/action_view/helpers/form_options_helper.rb +341 -166
- data/lib/action_view/helpers/form_tag_helper.rb +188 -88
- data/lib/action_view/helpers/javascript_helper.rb +23 -16
- data/lib/action_view/helpers/number_helper.rb +148 -354
- 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 -4
- data/lib/action_view/helpers/sanitize_helper.rb +3 -6
- data/lib/action_view/helpers/tag_helper.rb +43 -37
- data/lib/action_view/helpers/tags.rb +39 -0
- data/lib/action_view/helpers/tags/base.rb +148 -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 +41 -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/text_helper.rb +126 -113
- data/lib/action_view/helpers/translation_helper.rb +32 -16
- data/lib/action_view/helpers/url_helper.rb +200 -271
- 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 -39
- data/lib/action_view/model_naming.rb +12 -0
- data/lib/action_view/path_set.rb +9 -39
- 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 +10 -19
- data/lib/action_view/renderer/partial_renderer.rb +144 -81
- data/lib/action_view/renderer/renderer.rb +2 -19
- data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
- data/lib/action_view/renderer/template_renderer.rb +14 -13
- data/lib/action_view/routing_url_for.rb +107 -0
- data/lib/action_view/template.rb +22 -21
- data/lib/action_view/template/error.rb +22 -12
- data/lib/action_view/template/handlers.rb +12 -9
- data/lib/action_view/template/handlers/builder.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +11 -16
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/resolver.rb +111 -83
- data/lib/action_view/template/text.rb +12 -8
- data/lib/action_view/template/types.rb +57 -0
- data/lib/action_view/test_case.rb +66 -43
- data/lib/action_view/testing/resolvers.rb +3 -2
- data/lib/action_view/vendor/html-scanner.rb +20 -0
- 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 +18 -7
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
- 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
- metadata +135 -125
- 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.rb +0 -6
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class GroupedCollectionSelect < Base #:nodoc:
|
5
|
+
def initialize(object_name, method_name, template_object, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
6
|
+
@collection = collection
|
7
|
+
@group_method = group_method
|
8
|
+
@group_label_method = group_label_method
|
9
|
+
@option_key_method = option_key_method
|
10
|
+
@option_value_method = option_value_method
|
11
|
+
@html_options = html_options
|
12
|
+
|
13
|
+
super(object_name, method_name, template_object, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def render
|
17
|
+
option_tags_options = {
|
18
|
+
:selected => @options.fetch(:selected) { value(@object) },
|
19
|
+
:disabled => @options[:disabled]
|
20
|
+
}
|
21
|
+
|
22
|
+
select_content_tag(
|
23
|
+
option_groups_from_collection_for_select(@collection, @group_method, @group_label_method, @option_key_method, @option_value_method, option_tags_options), @options, @html_options
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class Label < Base #:nodoc:
|
5
|
+
def initialize(object_name, method_name, template_object, content_or_options = nil, options = nil)
|
6
|
+
options ||= {}
|
7
|
+
|
8
|
+
content_is_options = content_or_options.is_a?(Hash)
|
9
|
+
if content_is_options
|
10
|
+
options.merge! content_or_options
|
11
|
+
@content = nil
|
12
|
+
else
|
13
|
+
@content = content_or_options
|
14
|
+
end
|
15
|
+
|
16
|
+
super(object_name, method_name, template_object, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def render(&block)
|
20
|
+
options = @options.stringify_keys
|
21
|
+
tag_value = options.delete("value")
|
22
|
+
name_and_id = options.dup
|
23
|
+
|
24
|
+
if name_and_id["for"]
|
25
|
+
name_and_id["id"] = name_and_id["for"]
|
26
|
+
else
|
27
|
+
name_and_id.delete("id")
|
28
|
+
end
|
29
|
+
|
30
|
+
add_default_name_and_id_for_value(tag_value, name_and_id)
|
31
|
+
options.delete("index")
|
32
|
+
options.delete("namespace")
|
33
|
+
options["for"] = name_and_id["id"] unless options.key?("for")
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
content = @template_object.capture(&block)
|
37
|
+
else
|
38
|
+
content = if @content.blank?
|
39
|
+
@object_name.gsub!(/\[(.*)_attributes\]\[\d\]/, '.\1')
|
40
|
+
method_and_value = tag_value.present? ? "#{@method_name}.#{tag_value}" : @method_name
|
41
|
+
|
42
|
+
if object.respond_to?(:to_model)
|
43
|
+
key = object.class.model_name.i18n_key
|
44
|
+
i18n_default = ["#{key}.#{method_and_value}".to_sym, ""]
|
45
|
+
end
|
46
|
+
|
47
|
+
i18n_default ||= ""
|
48
|
+
I18n.t("#{@object_name}.#{method_and_value}", :default => i18n_default, :scope => "helpers.label").presence
|
49
|
+
else
|
50
|
+
@content.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
content ||= if object && object.class.respond_to?(:human_attribute_name)
|
54
|
+
object.class.human_attribute_name(@method_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
content ||= @method_name.humanize
|
58
|
+
end
|
59
|
+
|
60
|
+
label_tag(name_and_id["id"], content, options)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class NumberField < TextField #:nodoc:
|
5
|
+
def render
|
6
|
+
options = @options.stringify_keys
|
7
|
+
|
8
|
+
if range = options.delete("in") || options.delete("within")
|
9
|
+
options.update("min" => range.min, "max" => range.max)
|
10
|
+
end
|
11
|
+
|
12
|
+
@options = options
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'action_view/helpers/tags/checkable'
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module Helpers
|
5
|
+
module Tags
|
6
|
+
class RadioButton < Base #:nodoc:
|
7
|
+
include Checkable
|
8
|
+
|
9
|
+
def initialize(object_name, method_name, template_object, tag_value, options)
|
10
|
+
@tag_value = tag_value
|
11
|
+
super(object_name, method_name, template_object, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
options = @options.stringify_keys
|
16
|
+
options["type"] = "radio"
|
17
|
+
options["value"] = @tag_value
|
18
|
+
options["checked"] = "checked" if input_checked?(object, options)
|
19
|
+
add_default_name_and_id_for_value(@tag_value, options)
|
20
|
+
tag("input", options)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def checked?(value)
|
26
|
+
value.to_s == @tag_value.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class SearchField < TextField #:nodoc:
|
5
|
+
def render
|
6
|
+
options = @options.stringify_keys
|
7
|
+
|
8
|
+
if options["autosave"]
|
9
|
+
if options["autosave"] == true
|
10
|
+
options["autosave"] = request.host.split(".").reverse.join(".")
|
11
|
+
end
|
12
|
+
options["results"] ||= 10
|
13
|
+
end
|
14
|
+
|
15
|
+
if options["onsearch"]
|
16
|
+
options["incremental"] = true unless options.has_key?("incremental")
|
17
|
+
end
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class Select < Base #:nodoc:
|
5
|
+
def initialize(object_name, method_name, template_object, choices, options, html_options)
|
6
|
+
@choices = choices
|
7
|
+
@choices = @choices.to_a if @choices.is_a?(Range)
|
8
|
+
@html_options = html_options
|
9
|
+
|
10
|
+
super(object_name, method_name, template_object, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
option_tags_options = {
|
15
|
+
:selected => @options.fetch(:selected) { value(@object) },
|
16
|
+
:disabled => @options[:disabled]
|
17
|
+
}
|
18
|
+
|
19
|
+
option_tags = if grouped_choices?
|
20
|
+
grouped_options_for_select(@choices, option_tags_options)
|
21
|
+
else
|
22
|
+
options_for_select(@choices, option_tags_options)
|
23
|
+
end
|
24
|
+
|
25
|
+
select_content_tag(option_tags, @options, @html_options)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Grouped choices look like this:
|
31
|
+
#
|
32
|
+
# [nil, []]
|
33
|
+
# { nil => [] }
|
34
|
+
#
|
35
|
+
def grouped_choices?
|
36
|
+
!@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class TextArea < Base #:nodoc:
|
5
|
+
def render
|
6
|
+
options = @options.stringify_keys
|
7
|
+
add_default_name_and_id(options)
|
8
|
+
|
9
|
+
if size = options.delete("size")
|
10
|
+
options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
|
11
|
+
end
|
12
|
+
|
13
|
+
content_tag("textarea", options.delete('value') || value_before_type_cast(object), options)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class TextField < Base #:nodoc:
|
5
|
+
def render
|
6
|
+
options = @options.stringify_keys
|
7
|
+
options["size"] = options["maxlength"] unless options.key?("size")
|
8
|
+
options["type"] ||= field_type
|
9
|
+
options["value"] = options.fetch("value"){ value_before_type_cast(object) } unless field_type == "file"
|
10
|
+
options["value"] &&= ERB::Util.html_escape(options["value"])
|
11
|
+
add_default_name_and_id(options)
|
12
|
+
tag("input", options)
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def field_type
|
17
|
+
@field_type ||= self.name.split("::").last.sub("Field", "").downcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def field_type
|
24
|
+
self.class.field_type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module Tags
|
4
|
+
class TimeZoneSelect < Base #:nodoc:
|
5
|
+
def initialize(object_name, method_name, template_object, priority_zones, options, html_options)
|
6
|
+
@priority_zones = priority_zones
|
7
|
+
@html_options = html_options
|
8
|
+
|
9
|
+
super(object_name, method_name, template_object, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
select_content_tag(
|
14
|
+
time_zone_options_for_select(value(@object) || @options[:default], @priority_zones, @options[:model] || ActiveSupport::TimeZone), @options, @html_options
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -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. The
|
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. The
|
130
|
+
# <tt>:separator</tt> enable to choose the delimation. 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,32 @@ 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("<span>I'm allowed!</span> It's true.", {}, :
|
253
|
+
# simple_format("<span>I'm allowed!</span> It's true.", {}, sanitize: false)
|
265
254
|
# # => "<p><span>I'm allowed!</span> It's true.</p>"
|
266
|
-
def simple_format(text, html_options={}, options={})
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
255
|
+
def simple_format(text, html_options = {}, options = {})
|
256
|
+
wrapper_tag = options.fetch(:wrapper_tag, :p)
|
257
|
+
|
258
|
+
text = sanitize(text) if options.fetch(:sanitize, true)
|
259
|
+
paragraphs = split_paragraphs(text)
|
260
|
+
|
261
|
+
if paragraphs.empty?
|
262
|
+
content_tag(wrapper_tag, nil, html_options)
|
263
|
+
else
|
264
|
+
paragraphs.map { |paragraph|
|
265
|
+
content_tag(wrapper_tag, paragraph, html_options, options[:sanitize])
|
266
|
+
}.join("\n\n").html_safe
|
267
|
+
end
|
277
268
|
end
|
278
269
|
|
279
270
|
# Creates a Cycle object whose _to_s_ method cycles through elements of an
|
@@ -285,7 +276,6 @@ module ActionView
|
|
285
276
|
# and passing the name of the cycle. The current cycle string can be obtained
|
286
277
|
# anytime using the current_cycle method.
|
287
278
|
#
|
288
|
-
# ==== Examples
|
289
279
|
# # Alternate CSS classes for even and odd numbers...
|
290
280
|
# @items = [1,2,3,4]
|
291
281
|
# <table>
|
@@ -298,15 +288,15 @@ module ActionView
|
|
298
288
|
#
|
299
289
|
#
|
300
290
|
# # Cycle CSS classes for rows, and text colors for values within each row
|
301
|
-
# @items = x = [{:
|
302
|
-
# {:
|
303
|
-
# {:
|
291
|
+
# @items = x = [{first: 'Robert', middle: 'Daniel', last: 'James'},
|
292
|
+
# {first: 'Emily', middle: 'Shannon', maiden: 'Pike', last: 'Hicks'},
|
293
|
+
# {first: 'June', middle: 'Dae', last: 'Jones'}]
|
304
294
|
# <% @items.each do |item| %>
|
305
|
-
# <tr class="<%= cycle("odd", "even", :
|
295
|
+
# <tr class="<%= cycle("odd", "even", name: "row_class") -%>">
|
306
296
|
# <td>
|
307
297
|
# <% item.values.each do |value| %>
|
308
298
|
# <%# Create a named cycle "colors" %>
|
309
|
-
# <span style="color:<%= cycle("red", "green", "blue", :
|
299
|
+
# <span style="color:<%= cycle("red", "green", "blue", name: "colors") -%>">
|
310
300
|
# <%= value %>
|
311
301
|
# </span>
|
312
302
|
# <% end %>
|
@@ -315,12 +305,9 @@ module ActionView
|
|
315
305
|
# </tr>
|
316
306
|
# <% end %>
|
317
307
|
def cycle(first_value, *values)
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
else
|
322
|
-
name = "default"
|
323
|
-
end
|
308
|
+
options = values.extract_options!
|
309
|
+
name = options.fetch(:name, 'default')
|
310
|
+
|
324
311
|
values.unshift(first_value)
|
325
312
|
|
326
313
|
cycle = get_cycle(name)
|
@@ -334,7 +321,6 @@ module ActionView
|
|
334
321
|
# for complex table highlighting or any other design need which requires
|
335
322
|
# the current cycle string in more than one place.
|
336
323
|
#
|
337
|
-
# ==== Example
|
338
324
|
# # Alternate background colors
|
339
325
|
# @items = [1,2,3,4]
|
340
326
|
# <% @items.each do |item| %>
|
@@ -350,14 +336,13 @@ module ActionView
|
|
350
336
|
# Resets a cycle so that it starts from the first element the next time
|
351
337
|
# it is called. Pass in +name+ to reset a named cycle.
|
352
338
|
#
|
353
|
-
# ==== Example
|
354
339
|
# # Alternate CSS classes for even and odd numbers...
|
355
340
|
# @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
|
356
341
|
# <table>
|
357
342
|
# <% @items.each do |item| %>
|
358
343
|
# <tr class="<%= cycle("even", "odd") -%>">
|
359
344
|
# <% item.each do |value| %>
|
360
|
-
# <span style="color:<%= cycle("#333", "#666", "#999", :
|
345
|
+
# <span style="color:<%= cycle("#333", "#666", "#999", name: "colors") -%>">
|
361
346
|
# <%= value %>
|
362
347
|
# </span>
|
363
348
|
# <% end %>
|
@@ -421,6 +406,34 @@ module ActionView
|
|
421
406
|
@_cycles = Hash.new unless defined?(@_cycles)
|
422
407
|
@_cycles[name] = cycle_object
|
423
408
|
end
|
409
|
+
|
410
|
+
def split_paragraphs(text)
|
411
|
+
return [] if text.blank?
|
412
|
+
|
413
|
+
text.to_str.gsub(/\r\n?/, "\n").split(/\n\n+/).map! do |t|
|
414
|
+
t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def cut_excerpt_part(part_position, part, separator, options)
|
419
|
+
return "", "" unless part
|
420
|
+
|
421
|
+
radius = options.fetch(:radius, 100)
|
422
|
+
omission = options.fetch(:omission, "...")
|
423
|
+
|
424
|
+
part = part.split(separator)
|
425
|
+
part.delete("")
|
426
|
+
affix = part.size > radius ? omission : ""
|
427
|
+
|
428
|
+
part = if part_position == :first
|
429
|
+
drop_index = [part.length - radius, 0].max
|
430
|
+
part.drop(drop_index)
|
431
|
+
else
|
432
|
+
part.first(radius)
|
433
|
+
end
|
434
|
+
|
435
|
+
return affix, part.join(separator)
|
436
|
+
end
|
424
437
|
end
|
425
438
|
end
|
426
439
|
end
|