actionpack 2.0.5 → 2.1.0
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.
- data/CHANGELOG +149 -7
- data/MIT-LICENSE +1 -1
- data/README +1 -1
- data/Rakefile +5 -6
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions/model_assertions.rb +2 -1
- data/lib/action_controller/assertions/response_assertions.rb +4 -2
- data/lib/action_controller/assertions/routing_assertions.rb +3 -3
- data/lib/action_controller/assertions/selector_assertions.rb +30 -27
- data/lib/action_controller/assertions/tag_assertions.rb +3 -3
- data/lib/action_controller/base.rb +103 -129
- data/lib/action_controller/benchmarking.rb +3 -3
- data/lib/action_controller/caching.rb +41 -652
- data/lib/action_controller/caching/actions.rb +144 -0
- data/lib/action_controller/caching/fragments.rb +138 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sql_cache.rb +18 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/cgi_ext/cookie.rb +27 -23
- data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
- data/lib/action_controller/cgi_process.rb +6 -4
- data/lib/action_controller/components.rb +7 -6
- data/lib/action_controller/cookies.rb +31 -19
- data/lib/action_controller/dispatcher.rb +51 -84
- data/lib/action_controller/filters.rb +295 -421
- data/lib/action_controller/flash.rb +1 -6
- data/lib/action_controller/headers.rb +31 -0
- data/lib/action_controller/helpers.rb +26 -9
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +65 -13
- data/lib/action_controller/layout.rb +24 -39
- data/lib/action_controller/mime_responds.rb +7 -3
- data/lib/action_controller/mime_type.rb +25 -9
- data/lib/action_controller/mime_types.rb +1 -1
- data/lib/action_controller/polymorphic_routes.rb +32 -17
- data/lib/action_controller/record_identifier.rb +10 -4
- data/lib/action_controller/request.rb +46 -30
- data/lib/action_controller/request_forgery_protection.rb +10 -9
- data/lib/action_controller/request_profiler.rb +29 -8
- data/lib/action_controller/rescue.rb +24 -24
- data/lib/action_controller/resources.rb +66 -23
- data/lib/action_controller/response.rb +2 -2
- data/lib/action_controller/routing.rb +113 -1229
- data/lib/action_controller/routing/builder.rb +204 -0
- data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
- data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
- data/lib/action_controller/routing/route.rb +240 -0
- data/lib/action_controller/routing/route_set.rb +435 -0
- data/lib/action_controller/routing/routing_ext.rb +46 -0
- data/lib/action_controller/routing/segments.rb +283 -0
- data/lib/action_controller/session/active_record_store.rb +13 -8
- data/lib/action_controller/session/cookie_store.rb +20 -17
- data/lib/action_controller/session_management.rb +10 -3
- data/lib/action_controller/streaming.rb +45 -31
- data/lib/action_controller/test_case.rb +33 -23
- data/lib/action_controller/test_process.rb +39 -35
- data/lib/action_controller/url_rewriter.rb +18 -12
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +11 -3
- data/lib/action_view/base.rb +73 -390
- data/lib/action_view/helpers/active_record_helper.rb +83 -62
- data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
- data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
- data/lib/action_view/helpers/benchmark_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +3 -2
- data/lib/action_view/helpers/capture_helper.rb +1 -2
- data/lib/action_view/helpers/date_helper.rb +104 -82
- data/lib/action_view/helpers/form_helper.rb +148 -75
- data/lib/action_view/helpers/form_options_helper.rb +44 -23
- data/lib/action_view/helpers/form_tag_helper.rb +22 -13
- data/lib/action_view/helpers/javascripts/controls.js +1 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
- data/lib/action_view/helpers/javascripts/effects.js +1 -1
- data/lib/action_view/helpers/number_helper.rb +10 -3
- data/lib/action_view/helpers/prototype_helper.rb +61 -29
- data/lib/action_view/helpers/record_tag_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +23 -17
- data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
- data/lib/action_view/helpers/text_helper.rb +153 -125
- data/lib/action_view/helpers/url_helper.rb +83 -28
- data/lib/action_view/inline_template.rb +20 -0
- data/lib/action_view/partial_template.rb +70 -0
- data/lib/action_view/partials.rb +31 -73
- data/lib/action_view/template.rb +127 -0
- data/lib/action_view/template_error.rb +8 -7
- data/lib/action_view/template_finder.rb +177 -0
- data/lib/action_view/template_handler.rb +18 -1
- data/lib/action_view/template_handlers/builder.rb +10 -2
- data/lib/action_view/template_handlers/compilable.rb +128 -0
- data/lib/action_view/template_handlers/erb.rb +37 -2
- data/lib/action_view/template_handlers/rjs.rb +14 -1
- data/lib/action_view/test_case.rb +58 -0
- data/test/abstract_unit.rb +1 -1
- data/test/active_record_unit.rb +3 -6
- data/test/activerecord/active_record_store_test.rb +1 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
- data/test/adv_attr_test.rb +20 -0
- data/test/controller/action_pack_assertions_test.rb +16 -19
- data/test/controller/addresses_render_test.rb +1 -1
- data/test/controller/assert_select_test.rb +13 -6
- data/test/controller/base_test.rb +48 -2
- data/test/controller/benchmark_test.rb +1 -2
- data/test/controller/caching_test.rb +282 -21
- data/test/controller/capture_test.rb +1 -1
- data/test/controller/cgi_test.rb +1 -1
- data/test/controller/components_test.rb +1 -1
- data/test/controller/content_type_test.rb +2 -2
- data/test/controller/cookie_test.rb +13 -2
- data/test/controller/custom_handler_test.rb +14 -10
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
- data/test/controller/dispatcher_test.rb +31 -49
- data/test/controller/fake_controllers.rb +17 -0
- data/test/controller/fake_models.rb +6 -0
- data/test/controller/filter_params_test.rb +14 -8
- data/test/controller/filters_test.rb +44 -16
- data/test/controller/flash_test.rb +2 -2
- data/test/controller/header_test.rb +14 -0
- data/test/controller/helper_test.rb +19 -15
- data/test/controller/html-scanner/document_test.rb +1 -2
- data/test/controller/html-scanner/node_test.rb +1 -2
- data/test/controller/html-scanner/sanitizer_test.rb +8 -5
- data/test/controller/html-scanner/tag_node_test.rb +1 -2
- data/test/controller/html-scanner/text_node_test.rb +2 -3
- data/test/controller/html-scanner/tokenizer_test.rb +8 -2
- data/test/controller/http_authentication_test.rb +1 -1
- data/test/controller/integration_test.rb +14 -16
- data/test/controller/integration_upload_test.rb +43 -0
- data/test/controller/layout_test.rb +26 -6
- data/test/controller/mime_responds_test.rb +39 -7
- data/test/controller/mime_type_test.rb +29 -5
- data/test/controller/new_render_test.rb +105 -34
- data/test/controller/polymorphic_routes_test.rb +32 -20
- data/test/controller/record_identifier_test.rb +38 -2
- data/test/controller/redirect_test.rb +21 -1
- data/test/controller/render_test.rb +59 -15
- data/test/controller/request_forgery_protection_test.rb +92 -5
- data/test/controller/request_test.rb +64 -6
- data/test/controller/rescue_test.rb +22 -6
- data/test/controller/resources_test.rb +102 -14
- data/test/controller/routing_test.rb +231 -19
- data/test/controller/selector_test.rb +2 -2
- data/test/controller/send_file_test.rb +14 -3
- data/test/controller/session/cookie_store_test.rb +16 -4
- data/test/controller/session/mem_cache_store_test.rb +3 -4
- data/test/controller/session_fixation_test.rb +1 -1
- data/test/controller/session_management_test.rb +23 -1
- data/test/controller/test_test.rb +39 -18
- data/test/controller/url_rewriter_test.rb +35 -1
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -12
- data/test/controller/webservice_test.rb +48 -3
- data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
- data/test/fixtures/company.rb +1 -0
- data/test/fixtures/customers/_customer.html.erb +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/functional_caching/_partial.erb +3 -0
- data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
- data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
- data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
- data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
- data/test/fixtures/mascot.rb +3 -0
- data/test/fixtures/mascots.yml +4 -0
- data/test/fixtures/mascots/_mascot.html.erb +1 -0
- data/test/fixtures/multipart/boundary_problem_file +10 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/public/javascripts/controls.js +1 -0
- data/test/fixtures/public/javascripts/dragdrop.js +1 -0
- data/test/fixtures/public/javascripts/effects.js +1 -0
- data/test/fixtures/public/javascripts/prototype.js +1 -0
- data/test/fixtures/public/javascripts/version.1.0.js +1 -0
- data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
- data/test/fixtures/reply.rb +1 -0
- data/test/fixtures/shared.html.erb +1 -0
- data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
- data/test/fixtures/test/_customer_counter.erb +1 -0
- data/test/fixtures/test/_form.erb +1 -0
- data/test/fixtures/test/_labelling_form.erb +1 -0
- data/test/fixtures/test/_raise.html.erb +1 -0
- data/test/fixtures/test/greeting.js.rjs +1 -0
- data/test/fixtures/topics/_topic.html.erb +1 -0
- data/test/template/active_record_helper_test.rb +25 -8
- data/test/template/asset_tag_helper_test.rb +100 -17
- data/test/template/atom_feed_helper_test.rb +29 -1
- data/test/template/benchmark_helper_test.rb +10 -22
- data/test/template/date_helper_test.rb +455 -153
- data/test/template/erb_util_test.rb +10 -42
- data/test/template/form_helper_test.rb +192 -66
- data/test/template/form_options_helper_test.rb +19 -8
- data/test/template/form_tag_helper_test.rb +11 -8
- data/test/template/javascript_helper_test.rb +3 -9
- data/test/template/number_helper_test.rb +6 -3
- data/test/template/prototype_helper_test.rb +27 -40
- data/test/template/record_tag_helper_test.rb +54 -0
- data/test/template/sanitize_helper_test.rb +5 -6
- data/test/template/scriptaculous_helper_test.rb +7 -13
- data/test/template/tag_helper_test.rb +3 -6
- data/test/template/template_finder_test.rb +73 -0
- data/test/template/template_object_test.rb +95 -0
- data/test/template/test_test.rb +56 -0
- data/test/template/text_helper_test.rb +46 -33
- data/test/template/url_helper_test.rb +8 -10
- metadata +65 -12
- data/lib/action_view/compiled_templates.rb +0 -69
- data/test/action_view_test.rb +0 -44
- data/test/activerecord/fixtures_test.rb +0 -24
- data/test/controller/fragment_store_setting_test.rb +0 -47
- data/test/template/compiled_templates_test.rb +0 -197
- data/test/template/deprecate_ivars_test.rb +0 -51
@@ -26,17 +26,17 @@ module ActionView
|
|
26
26
|
# :url => { :action => "reload" },
|
27
27
|
# :complete => visual_effect(:highlight, "posts", :duration => 0.5)
|
28
28
|
#
|
29
|
-
# If no element_id is given, it assumes "element" which should be a local
|
29
|
+
# If no +element_id+ is given, it assumes "element" which should be a local
|
30
30
|
# variable in the generated JavaScript execution context. This can be
|
31
|
-
# used for example with drop_receiving_element
|
31
|
+
# used for example with +drop_receiving_element+:
|
32
32
|
#
|
33
33
|
# <%= drop_receiving_element (...), :loading => visual_effect(:fade) %>
|
34
34
|
#
|
35
35
|
# This would fade the element that was dropped on the drop receiving
|
36
36
|
# element.
|
37
37
|
#
|
38
|
-
# For toggling visual effects, you can use
|
39
|
-
#
|
38
|
+
# For toggling visual effects, you can use <tt>:toggle_appear</tt>, <tt>:toggle_slide</tt>, and
|
39
|
+
# <tt>:toggle_blind</tt> which will alternate between appear/fade, slidedown/slideup, and
|
40
40
|
# blinddown/blindup respectively.
|
41
41
|
#
|
42
42
|
# You can change the behaviour with various options, see
|
@@ -67,6 +67,7 @@ module ActionView
|
|
67
67
|
# element as parameters.
|
68
68
|
#
|
69
69
|
# Example:
|
70
|
+
#
|
70
71
|
# <%= sortable_element("my_list", :url => { :action => "order" }) %>
|
71
72
|
#
|
72
73
|
# In the example, the action gets a "my_list" array parameter
|
@@ -79,60 +80,56 @@ module ActionView
|
|
79
80
|
#
|
80
81
|
# Additional +options+ are:
|
81
82
|
#
|
82
|
-
# <tt>:format</tt
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
# <tt>:
|
90
|
-
#
|
91
|
-
#
|
92
|
-
# <tt
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
# <tt>:onUpdate</tt>:: Called when the drag ends and the Sortable's order is
|
133
|
-
# changed in any way. When dragging from one Sortable to
|
134
|
-
# another, the callback is called once on each Sortable. Gets
|
135
|
-
# the container as its parameter.
|
83
|
+
# * <tt>:format</tt> - A regular expression to determine what to send as the
|
84
|
+
# serialized id to the server (the default is <tt>/^[^_]*_(.*)$/</tt>).
|
85
|
+
#
|
86
|
+
# * <tt>:constraint</tt> - Whether to constrain the dragging to either
|
87
|
+
# <tt>:horizontal</tt> or <tt>:vertical</tt> (or false to make it unconstrained).
|
88
|
+
#
|
89
|
+
# * <tt>:overlap</tt> - Calculate the item overlap in the <tt>:horizontal</tt>
|
90
|
+
# or <tt>:vertical</tt> direction.
|
91
|
+
#
|
92
|
+
# * <tt>:tag</tt> - Which children of the container element to treat as
|
93
|
+
# sortable (default is <tt>li</tt>).
|
94
|
+
#
|
95
|
+
# * <tt>:containment</tt> - Takes an element or array of elements to treat as
|
96
|
+
# potential drop targets (defaults to the original target element).
|
97
|
+
#
|
98
|
+
# * <tt>:only</tt> - A CSS class name or arry of class names used to filter
|
99
|
+
# out child elements as candidates.
|
100
|
+
#
|
101
|
+
# * <tt>:scroll</tt> - Determines whether to scroll the list during drag
|
102
|
+
# operations if the list runs past the visual border.
|
103
|
+
#
|
104
|
+
# * <tt>:tree</tt> - Determines whether to treat nested lists as part of the
|
105
|
+
# main sortable list. This means that you can create multi-layer lists,
|
106
|
+
# and not only sort items at the same level, but drag and sort items
|
107
|
+
# between levels.
|
108
|
+
#
|
109
|
+
# * <tt>:hoverclass</tt> - If set, the Droppable will have this additional CSS class
|
110
|
+
# when an accepted Draggable is hovered over it.
|
111
|
+
#
|
112
|
+
# * <tt>:handle</tt> - Sets whether the element should only be draggable by an
|
113
|
+
# embedded handle. The value may be a string referencing a CSS class value
|
114
|
+
# (as of script.aculo.us V1.5). The first child/grandchild/etc. element
|
115
|
+
# found within the element that has this CSS class value will be used as
|
116
|
+
# the handle.
|
117
|
+
#
|
118
|
+
# * <tt>:ghosting</tt> - Clones the element and drags the clone, leaving
|
119
|
+
# the original in place until the clone is dropped (default is <tt>false</tt>).
|
120
|
+
#
|
121
|
+
# * <tt>:dropOnEmpty</tt> - If true the Sortable container will be made into
|
122
|
+
# a Droppable, that can receive a Draggable (as according to the containment
|
123
|
+
# rules) as a child element when there are no more elements inside (default
|
124
|
+
# is <tt>false</tt>).
|
125
|
+
#
|
126
|
+
# * <tt>:onChange</tt> - Called whenever the sort order changes while dragging. When
|
127
|
+
# dragging from one Sortable to another, the callback is called once on each
|
128
|
+
# Sortable. Gets the affected element as its parameter.
|
129
|
+
#
|
130
|
+
# * <tt>:onUpdate</tt> - Called when the drag ends and the Sortable's order is
|
131
|
+
# changed in any way. When dragging from one Sortable to another, the callback
|
132
|
+
# is called once on each Sortable. Gets the container as its parameter.
|
136
133
|
#
|
137
134
|
# See http://script.aculo.us for more documentation.
|
138
135
|
def sortable_element(element_id, options = {})
|
@@ -170,8 +167,8 @@ module ActionView
|
|
170
167
|
end
|
171
168
|
|
172
169
|
# Makes the element with the DOM ID specified by +element_id+ receive
|
173
|
-
# dropped draggable elements (created by draggable_element).
|
174
|
-
# and make an AJAX call
|
170
|
+
# dropped draggable elements (created by +draggable_element+).
|
171
|
+
# and make an AJAX call. By default, the action called gets the DOM ID
|
175
172
|
# of the element as parameter.
|
176
173
|
#
|
177
174
|
# Example:
|
@@ -180,6 +177,32 @@ module ActionView
|
|
180
177
|
#
|
181
178
|
# You can change the behaviour with various options, see
|
182
179
|
# http://script.aculo.us for more documentation.
|
180
|
+
#
|
181
|
+
# Some of these +options+ include:
|
182
|
+
# * <tt>:accept</tt> - Set this to a string or an array of strings describing the
|
183
|
+
# allowable CSS classes that the +draggable_element+ must have in order
|
184
|
+
# to be accepted by this +drop_receiving_element+.
|
185
|
+
#
|
186
|
+
# * <tt>:confirm</tt> - Adds a confirmation dialog. Example:
|
187
|
+
#
|
188
|
+
# :confirm => "Are you sure you want to do this?"
|
189
|
+
#
|
190
|
+
# * <tt>:hoverclass</tt> - If set, the +drop_receiving_element+ will have
|
191
|
+
# this additional CSS class when an accepted +draggable_element+ is
|
192
|
+
# hovered over it.
|
193
|
+
#
|
194
|
+
# * <tt>:onDrop</tt> - Called when a +draggable_element+ is dropped onto
|
195
|
+
# this element. Override this callback with a JavaScript expression to
|
196
|
+
# change the default drop behavour. Example:
|
197
|
+
#
|
198
|
+
# :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }"
|
199
|
+
#
|
200
|
+
# This callback gets three parameters: The Draggable element, the Droppable
|
201
|
+
# element and the Event object. You can extract additional information about
|
202
|
+
# the drop - like if the Ctrl or Shift keys were pressed - from the Event object.
|
203
|
+
#
|
204
|
+
# * <tt>:with</tt> - A JavaScript expression specifying the parameters for
|
205
|
+
# the XMLHttpRequest. Any expressions should return a valid URL query string.
|
183
206
|
def drop_receiving_element(element_id, options = {})
|
184
207
|
javascript_tag(drop_receiving_element_js(element_id, options).chop!)
|
185
208
|
end
|
@@ -192,6 +215,9 @@ module ActionView
|
|
192
215
|
options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
|
193
216
|
options[:hoverclass] = "'#{options[:hoverclass]}'" if options[:hoverclass]
|
194
217
|
|
218
|
+
# Confirmation happens during the onDrop callback, so it can be removed from the options
|
219
|
+
options.delete(:confirm) if options[:confirm]
|
220
|
+
|
195
221
|
%(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});)
|
196
222
|
end
|
197
223
|
end
|
@@ -3,19 +3,19 @@ require 'html/document'
|
|
3
3
|
|
4
4
|
module ActionView
|
5
5
|
module Helpers #:nodoc:
|
6
|
-
# The TextHelper module provides a set of methods for filtering, formatting
|
7
|
-
# and transforming strings, which can reduce the amount of inline Ruby code in
|
8
|
-
# your views. These helper methods extend ActionView making them callable
|
6
|
+
# The TextHelper module provides a set of methods for filtering, formatting
|
7
|
+
# and transforming strings, which can reduce the amount of inline Ruby code in
|
8
|
+
# your views. These helper methods extend ActionView making them callable
|
9
9
|
# within your template files.
|
10
|
-
module TextHelper
|
11
|
-
# The preferred method of outputting text in your views is to use the
|
12
|
-
# <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
|
13
|
-
# do not operate as expected in an eRuby code block. If you absolutely must
|
10
|
+
module TextHelper
|
11
|
+
# The preferred method of outputting text in your views is to use the
|
12
|
+
# <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
|
13
|
+
# do not operate as expected in an eRuby code block. If you absolutely must
|
14
14
|
# output text within a non-output code block (i.e., <% %>), you can use the concat method.
|
15
15
|
#
|
16
16
|
# ==== Examples
|
17
|
-
# <%
|
18
|
-
# concat "hello", binding
|
17
|
+
# <%
|
18
|
+
# concat "hello", binding
|
19
19
|
# # is the equivalent of <%= "hello" %>
|
20
20
|
#
|
21
21
|
# if (logged_in == true):
|
@@ -29,43 +29,54 @@ module ActionView
|
|
29
29
|
eval(ActionView::Base.erb_variable, binding) << string
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
32
|
+
if RUBY_VERSION < '1.9'
|
33
|
+
# If +text+ is longer than +length+, +text+ will be truncated to the length of
|
34
|
+
# +length+ (defaults to 30) and the last characters will be replaced with the +truncate_string+
|
35
|
+
# (defaults to "...").
|
36
|
+
#
|
37
|
+
# ==== Examples
|
38
|
+
# truncate("Once upon a time in a world far far away", 14)
|
39
|
+
# # => Once upon a...
|
40
|
+
#
|
41
|
+
# truncate("Once upon a time in a world far far away")
|
42
|
+
# # => Once upon a time in a world f...
|
43
|
+
#
|
44
|
+
# truncate("And they found that many people were sleeping better.", 25, "(clipped)")
|
45
|
+
# # => And they found that many (clipped)
|
46
|
+
#
|
47
|
+
# truncate("And they found that many people were sleeping better.", 15, "... (continued)")
|
48
|
+
# # => And they found... (continued)
|
49
|
+
def truncate(text, length = 30, truncate_string = "...")
|
50
|
+
if text
|
51
|
+
l = length - truncate_string.chars.length
|
52
|
+
chars = text.chars
|
53
|
+
(chars.length > length ? chars[0...l] + truncate_string : text).to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
def truncate(text, length = 30, truncate_string = "...") #:nodoc:
|
58
|
+
if text
|
59
|
+
l = length - truncate_string.length
|
60
|
+
(text.length > length ? text[0...l] + truncate_string : text).to_s
|
61
|
+
end
|
62
|
+
end
|
52
63
|
end
|
53
64
|
|
54
65
|
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
|
55
|
-
# a +highlighter+ string. The highlighter can be specialized by passing +highlighter+
|
66
|
+
# a +highlighter+ string. The highlighter can be specialized by passing +highlighter+
|
56
67
|
# as a single-quoted string with \1 where the phrase is to be inserted (defaults to
|
57
68
|
# '<strong class="highlight">\1</strong>')
|
58
69
|
#
|
59
70
|
# ==== Examples
|
60
|
-
# highlight('You searched for: rails', 'rails')
|
71
|
+
# highlight('You searched for: rails', 'rails')
|
61
72
|
# # => You searched for: <strong class="highlight">rails</strong>
|
62
73
|
#
|
63
74
|
# highlight('You searched for: ruby, rails, dhh', 'actionpack')
|
64
|
-
# # => You searched for: ruby, rails, dhh
|
75
|
+
# # => You searched for: ruby, rails, dhh
|
65
76
|
#
|
66
|
-
# highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
|
77
|
+
# highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
|
67
78
|
# # => You searched <em>for</em>: <em>rails</em>
|
68
|
-
#
|
79
|
+
#
|
69
80
|
# highlight('You searched for: rails', 'rails', "<a href='search?q=\1'>\1</a>")
|
70
81
|
# # => You searched for: <a href='search?q=rails>rails</a>
|
71
82
|
def highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>')
|
@@ -77,71 +88,83 @@ module ActionView
|
|
77
88
|
end
|
78
89
|
end
|
79
90
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
91
|
+
if RUBY_VERSION < '1.9'
|
92
|
+
# Extracts an excerpt from +text+ that matches the first instance of +phrase+.
|
93
|
+
# The +radius+ expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
|
94
|
+
# defined in +radius+ (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
|
95
|
+
# then the +excerpt_string+ will be prepended/appended accordingly. The resulting string will be stripped in any case.
|
96
|
+
# If the +phrase+ isn't found, nil is returned.
|
97
|
+
#
|
98
|
+
# ==== Examples
|
99
|
+
# excerpt('This is an example', 'an', 5)
|
100
|
+
# # => "...s is an exam..."
|
101
|
+
#
|
102
|
+
# excerpt('This is an example', 'is', 5)
|
103
|
+
# # => "This is a..."
|
104
|
+
#
|
105
|
+
# excerpt('This is an example', 'is')
|
106
|
+
# # => "This is an example"
|
107
|
+
#
|
108
|
+
# excerpt('This next thing is an example', 'ex', 2)
|
109
|
+
# # => "...next..."
|
110
|
+
#
|
111
|
+
# excerpt('This is also an example', 'an', 8, '<chop> ')
|
112
|
+
# # => "<chop> is also an example"
|
113
|
+
def excerpt(text, phrase, radius = 100, excerpt_string = "...")
|
114
|
+
if text && phrase
|
115
|
+
phrase = Regexp.escape(phrase)
|
104
116
|
|
105
|
-
|
106
|
-
|
107
|
-
|
117
|
+
if found_pos = text.chars =~ /(#{phrase})/i
|
118
|
+
start_pos = [ found_pos - radius, 0 ].max
|
119
|
+
end_pos = [ [ found_pos + phrase.chars.length + radius - 1, 0].max, text.chars.length ].min
|
108
120
|
|
109
|
-
|
110
|
-
|
121
|
+
prefix = start_pos > 0 ? excerpt_string : ""
|
122
|
+
postfix = end_pos < text.chars.length - 1 ? excerpt_string : ""
|
111
123
|
|
112
|
-
|
113
|
-
|
114
|
-
|
124
|
+
prefix + text.chars[start_pos..end_pos].strip + postfix
|
125
|
+
else
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
else
|
131
|
+
def excerpt(text, phrase, radius = 100, excerpt_string = "...") #:nodoc:
|
132
|
+
if text && phrase
|
133
|
+
phrase = Regexp.escape(phrase)
|
134
|
+
|
135
|
+
if found_pos = text =~ /(#{phrase})/i
|
136
|
+
start_pos = [ found_pos - radius, 0 ].max
|
137
|
+
end_pos = [ [ found_pos + phrase.length + radius - 1, 0].max, text.length ].min
|
138
|
+
|
139
|
+
prefix = start_pos > 0 ? excerpt_string : ""
|
140
|
+
postfix = end_pos < text.length - 1 ? excerpt_string : ""
|
141
|
+
|
142
|
+
prefix + text[start_pos..end_pos].strip + postfix
|
143
|
+
else
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
end
|
115
147
|
end
|
116
148
|
end
|
117
149
|
|
118
|
-
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
119
|
-
# is supplied, it will use that when count is > 1,
|
120
|
-
#
|
121
|
-
# it will just add an 's' to the +singular+ word.
|
150
|
+
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
151
|
+
# +plural+ is supplied, it will use that when count is > 1, otherwise
|
152
|
+
# it will use the Inflector to determine the plural form
|
122
153
|
#
|
123
154
|
# ==== Examples
|
124
|
-
# pluralize(1, 'person')
|
155
|
+
# pluralize(1, 'person')
|
125
156
|
# # => 1 person
|
126
157
|
#
|
127
|
-
# pluralize(2, 'person')
|
158
|
+
# pluralize(2, 'person')
|
128
159
|
# # => 2 people
|
129
160
|
#
|
130
|
-
# pluralize(3, 'person', 'users')
|
161
|
+
# pluralize(3, 'person', 'users')
|
131
162
|
# # => 3 users
|
132
163
|
#
|
133
164
|
# pluralize(0, 'person')
|
134
165
|
# # => 0 people
|
135
166
|
def pluralize(count, singular, plural = nil)
|
136
|
-
|
137
|
-
singular
|
138
|
-
elsif plural
|
139
|
-
plural
|
140
|
-
elsif Object.const_defined?("Inflector")
|
141
|
-
Inflector.pluralize(singular)
|
142
|
-
else
|
143
|
-
singular + "s"
|
144
|
-
end
|
167
|
+
"#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
|
145
168
|
end
|
146
169
|
|
147
170
|
# Wraps the +text+ into lines no longer than +line_width+ width. This method
|
@@ -197,7 +220,7 @@ module ActionView
|
|
197
220
|
end
|
198
221
|
end
|
199
222
|
|
200
|
-
# Returns the text with all the Textile codes turned into HTML tags,
|
223
|
+
# Returns the text with all the Textile codes turned into HTML tags,
|
201
224
|
# but without the bounding <p> tag that RedCloth adds.
|
202
225
|
#
|
203
226
|
# You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
|
@@ -241,57 +264,62 @@ module ActionView
|
|
241
264
|
# # => "<p>We like to <em>write</em> <code>code</code>, not just <em>read</em> it!</p>"
|
242
265
|
#
|
243
266
|
# markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
|
244
|
-
# # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
|
267
|
+
# # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
|
245
268
|
# # has more information.</p>"
|
246
269
|
#
|
247
270
|
# markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
|
248
|
-
# # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
|
271
|
+
# # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
|
249
272
|
def markdown(text)
|
250
273
|
text.blank? ? "" : BlueCloth.new(text).to_html
|
251
274
|
end
|
252
275
|
rescue LoadError
|
253
276
|
# We can't really help what's not there
|
254
277
|
end
|
255
|
-
|
278
|
+
|
256
279
|
# Returns +text+ transformed into HTML using simple formatting rules.
|
257
|
-
# Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a
|
280
|
+
# Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a
|
258
281
|
# paragraph and wrapped in <tt><p></tt> tags. One newline (<tt>\n</tt>) is
|
259
282
|
# considered as a linebreak and a <tt><br /></tt> tag is appended. This
|
260
|
-
# method does not remove the newlines from the +text+.
|
283
|
+
# method does not remove the newlines from the +text+.
|
261
284
|
#
|
285
|
+
# You can pass any HTML attributes into <tt>html_options</tt>. These
|
286
|
+
# will be added to all created paragraphs.
|
262
287
|
# ==== Examples
|
263
|
-
# my_text = "
|
264
|
-
# ...with a line break."""
|
288
|
+
# my_text = "Here is some basic text...\n...with a line break."
|
265
289
|
#
|
266
290
|
# simple_format(my_text)
|
267
|
-
# # => "<p>Here is some basic text
|
291
|
+
# # => "<p>Here is some basic text...\n<br />...with a line break.</p>"
|
268
292
|
#
|
269
|
-
# more_text = "
|
270
|
-
#
|
271
|
-
# ...right there."""
|
293
|
+
# more_text = "We want to put a paragraph...\n\n...right there."
|
272
294
|
#
|
273
295
|
# simple_format(more_text)
|
274
|
-
# # => "<p>We want to put a paragraph...</p
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
296
|
+
# # => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"
|
297
|
+
#
|
298
|
+
# simple_format("Look ma! A class!", :class => 'description')
|
299
|
+
# # => "<p class='description'>Look ma! A class!</p>"
|
300
|
+
def simple_format(text, html_options={})
|
301
|
+
start_tag = tag('p', html_options, true)
|
302
|
+
text = text.to_s.dup
|
303
|
+
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
|
304
|
+
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
|
305
|
+
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
306
|
+
text.insert 0, start_tag
|
307
|
+
text << "</p>"
|
280
308
|
end
|
281
309
|
|
282
|
-
# Turns all URLs and e-mail addresses into clickable links. The +link+ parameter
|
310
|
+
# Turns all URLs and e-mail addresses into clickable links. The +link+ parameter
|
283
311
|
# will limit what should be linked. You can add HTML attributes to the links using
|
284
|
-
# +href_options+. Options for +link+ are <tt>:all</tt> (default),
|
285
|
-
# <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
|
312
|
+
# +href_options+. Options for +link+ are <tt>:all</tt> (default),
|
313
|
+
# <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
|
286
314
|
# e-mail address is yielded and the result is used as the link text.
|
287
315
|
#
|
288
316
|
# ==== Examples
|
289
|
-
# auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
|
317
|
+
# auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
|
290
318
|
# # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
|
291
319
|
# # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
292
320
|
#
|
293
321
|
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :urls)
|
294
|
-
# # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
|
322
|
+
# # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
|
295
323
|
# # or e-mail david@loudthinking.com"
|
296
324
|
#
|
297
325
|
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :email_addresses)
|
@@ -301,9 +329,9 @@ module ActionView
|
|
301
329
|
# auto_link(post_body, :all, :target => '_blank') do |text|
|
302
330
|
# truncate(text, 15)
|
303
331
|
# end
|
304
|
-
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
|
332
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
|
305
333
|
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
306
|
-
#
|
334
|
+
#
|
307
335
|
def auto_link(text, link = :all, href_options = {}, &block)
|
308
336
|
return '' if text.blank?
|
309
337
|
case link
|
@@ -312,15 +340,15 @@ module ActionView
|
|
312
340
|
when :urls then auto_link_urls(text, href_options, &block)
|
313
341
|
end
|
314
342
|
end
|
315
|
-
|
343
|
+
|
316
344
|
# Creates a Cycle object whose _to_s_ method cycles through elements of an
|
317
|
-
# array every time it is called. This can be used for example, to alternate
|
318
|
-
# classes for table rows. You can use named cycles to allow nesting in loops.
|
319
|
-
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
|
320
|
-
# named cycle. You can manually reset a cycle by calling reset_cycle and passing the
|
345
|
+
# array every time it is called. This can be used for example, to alternate
|
346
|
+
# classes for table rows. You can use named cycles to allow nesting in loops.
|
347
|
+
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
|
348
|
+
# named cycle. You can manually reset a cycle by calling reset_cycle and passing the
|
321
349
|
# name of the cycle.
|
322
350
|
#
|
323
|
-
# ==== Examples
|
351
|
+
# ==== Examples
|
324
352
|
# # Alternate CSS classes for even and odd numbers...
|
325
353
|
# @items = [1,2,3,4]
|
326
354
|
# <table>
|
@@ -333,8 +361,8 @@ module ActionView
|
|
333
361
|
#
|
334
362
|
#
|
335
363
|
# # Cycle CSS classes for rows, and text colors for values within each row
|
336
|
-
# @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
|
337
|
-
# {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
|
364
|
+
# @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
|
365
|
+
# {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
|
338
366
|
# {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
|
339
367
|
# <% @items.each do |item| %>
|
340
368
|
# <tr class="<%= cycle("even", "odd", :name => "row_class") -%>">
|
@@ -364,8 +392,8 @@ module ActionView
|
|
364
392
|
end
|
365
393
|
return cycle.to_s
|
366
394
|
end
|
367
|
-
|
368
|
-
# Resets a cycle so that it starts from the first element the next time
|
395
|
+
|
396
|
+
# Resets a cycle so that it starts from the first element the next time
|
369
397
|
# it is called. Pass in +name+ to reset a named cycle.
|
370
398
|
#
|
371
399
|
# ==== Example
|
@@ -391,12 +419,12 @@ module ActionView
|
|
391
419
|
|
392
420
|
class Cycle #:nodoc:
|
393
421
|
attr_reader :values
|
394
|
-
|
422
|
+
|
395
423
|
def initialize(first_value, *values)
|
396
424
|
@values = values.unshift(first_value)
|
397
425
|
reset
|
398
426
|
end
|
399
|
-
|
427
|
+
|
400
428
|
def reset
|
401
429
|
@index = 0
|
402
430
|
end
|
@@ -416,7 +444,7 @@ module ActionView
|
|
416
444
|
@_cycles = Hash.new unless defined?(@_cycles)
|
417
445
|
return @_cycles[name]
|
418
446
|
end
|
419
|
-
|
447
|
+
|
420
448
|
def set_cycle(name, cycle_object)
|
421
449
|
@_cycles = Hash.new unless defined?(@_cycles)
|
422
450
|
@_cycles[name] = cycle_object
|
@@ -425,22 +453,22 @@ module ActionView
|
|
425
453
|
AUTO_LINK_RE = %r{
|
426
454
|
( # leading text
|
427
455
|
<\w+.*?>| # leading HTML tag, or
|
428
|
-
[^=!:'"/]| # leading punctuation, or
|
456
|
+
[^=!:'"/]| # leading punctuation, or
|
429
457
|
^ # beginning of line
|
430
458
|
)
|
431
459
|
(
|
432
460
|
(?:https?://)| # protocol spec, or
|
433
461
|
(?:www\.) # www.*
|
434
|
-
)
|
462
|
+
)
|
435
463
|
(
|
436
464
|
[-\w]+ # subdomain or domain
|
437
465
|
(?:\.[-\w]+)* # remaining subdomains or domain
|
438
466
|
(?::\d+)? # port
|
439
|
-
(?:/(?:(?:[~\w
|
467
|
+
(?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:][^\s$]))+)?)* # path
|
440
468
|
(?:\?[\w\+@%&=.;-]+)? # query string
|
441
469
|
(?:\#[\w\-]*)? # trailing anchor
|
442
470
|
)
|
443
|
-
([[:punct:]]
|
471
|
+
([[:punct:]]|<|$|) # trailing text
|
444
472
|
}x unless const_defined?(:AUTO_LINK_RE)
|
445
473
|
|
446
474
|
# Turns all urls into clickable links. If a block is given, each url
|
@@ -465,7 +493,7 @@ module ActionView
|
|
465
493
|
body = text.dup
|
466
494
|
text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
|
467
495
|
text = $1
|
468
|
-
|
496
|
+
|
469
497
|
if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
|
470
498
|
text
|
471
499
|
else
|