actionview 4.2.11.1 → 7.0.2.4
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.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +5 -3
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +18 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +12 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +29 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +14 -10
- data/lib/action_view/template/html.rb +12 -13
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +139 -300
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,11 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cgi"
|
4
|
+
require "action_view/helpers/url_helper"
|
5
|
+
require "action_view/helpers/text_helper"
|
6
|
+
require "active_support/core_ext/string/output_safety"
|
7
|
+
require "active_support/core_ext/module/attribute_accessors"
|
5
8
|
|
6
9
|
module ActionView
|
7
10
|
# = Action View Form Tag Helpers
|
8
|
-
module Helpers
|
11
|
+
module Helpers # :nodoc:
|
9
12
|
# Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like
|
10
13
|
# FormHelper does. Instead, you provide the names and values manually.
|
11
14
|
#
|
@@ -18,9 +21,11 @@ module ActionView
|
|
18
21
|
include TextHelper
|
19
22
|
|
20
23
|
mattr_accessor :embed_authenticity_token_in_remote_forms
|
21
|
-
self.embed_authenticity_token_in_remote_forms =
|
24
|
+
self.embed_authenticity_token_in_remote_forms = nil
|
25
|
+
|
26
|
+
mattr_accessor :default_enforce_utf8, default: true
|
22
27
|
|
23
|
-
# Starts a form tag that points the action to
|
28
|
+
# Starts a form tag that points the action to a URL configured with <tt>url_for_options</tt> just like
|
24
29
|
# ActionController::Base#url_for. The method for the form defaults to POST.
|
25
30
|
#
|
26
31
|
# ==== Options
|
@@ -58,6 +63,9 @@ module ActionView
|
|
58
63
|
# <%= form_tag('/posts', remote: true) %>
|
59
64
|
# # => <form action="/posts" method="post" data-remote="true">
|
60
65
|
#
|
66
|
+
# form_tag(false, method: :get)
|
67
|
+
# # => <form method="get">
|
68
|
+
#
|
61
69
|
# form_tag('http://far.away.com/form', authenticity_token: false)
|
62
70
|
# # form without authenticity token
|
63
71
|
#
|
@@ -73,6 +81,65 @@ module ActionView
|
|
73
81
|
end
|
74
82
|
end
|
75
83
|
|
84
|
+
# Generate an HTML <tt>id</tt> attribute value for the given name and
|
85
|
+
# field combination
|
86
|
+
#
|
87
|
+
# Return the value generated by the <tt>FormBuilder</tt> for the given
|
88
|
+
# attribute name.
|
89
|
+
#
|
90
|
+
# <%= label_tag :post, :title %>
|
91
|
+
# <%= text_field_tag :post, :title, aria: { describedby: field_id(:post, :title, :error) } %>
|
92
|
+
# <%= tag.span("is blank", id: field_id(:post, :title, :error) %>
|
93
|
+
#
|
94
|
+
# In the example above, the <tt><input type="text"></tt> element built by
|
95
|
+
# the call to <tt>text_field_tag</tt> declares an
|
96
|
+
# <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
|
97
|
+
# element, sharing a common <tt>id</tt> root (<tt>post_title</tt>, in this
|
98
|
+
# case).
|
99
|
+
def field_id(object_name, method_name, *suffixes, index: nil, namespace: nil)
|
100
|
+
if object_name.respond_to?(:model_name)
|
101
|
+
object_name = object_name.model_name.singular
|
102
|
+
end
|
103
|
+
|
104
|
+
sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
|
105
|
+
|
106
|
+
sanitized_method_name = method_name.to_s.delete_suffix("?")
|
107
|
+
|
108
|
+
[
|
109
|
+
namespace,
|
110
|
+
sanitized_object_name.presence,
|
111
|
+
(index unless sanitized_object_name.empty?),
|
112
|
+
sanitized_method_name,
|
113
|
+
*suffixes,
|
114
|
+
].tap(&:compact!).join("_")
|
115
|
+
end
|
116
|
+
|
117
|
+
# Generate an HTML <tt>name</tt> attribute value for the given name and
|
118
|
+
# field combination
|
119
|
+
#
|
120
|
+
# Return the value generated by the <tt>FormBuilder</tt> for the given
|
121
|
+
# attribute name.
|
122
|
+
#
|
123
|
+
# <%= text_field_tag :post, :title, name: field_name(:post, :title, :subtitle) %>
|
124
|
+
# <%# => <input type="text" name="post[title][subtitle]">
|
125
|
+
#
|
126
|
+
# <%= text_field_tag :post, :tag, name: field_name(:post, :tag, multiple: true) %>
|
127
|
+
# <%# => <input type="text" name="post[tag][]">
|
128
|
+
#
|
129
|
+
def field_name(object_name, method_name, *method_names, multiple: false, index: nil)
|
130
|
+
names = method_names.map! { |name| "[#{name}]" }.join
|
131
|
+
|
132
|
+
# a little duplication to construct fewer strings
|
133
|
+
case
|
134
|
+
when object_name.empty?
|
135
|
+
"#{method_name}#{names}#{multiple ? "[]" : ""}"
|
136
|
+
when index
|
137
|
+
"#{object_name}[#{index}][#{method_name}]#{names}#{multiple ? "[]" : ""}"
|
138
|
+
else
|
139
|
+
"#{object_name}[#{method_name}]#{names}#{multiple ? "[]" : ""}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
76
143
|
# Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
|
77
144
|
# choice selection box.
|
78
145
|
#
|
@@ -80,7 +147,7 @@ module ActionView
|
|
80
147
|
# associated records. <tt>option_tags</tt> is a string containing the option tags for the select box.
|
81
148
|
#
|
82
149
|
# ==== Options
|
83
|
-
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
|
150
|
+
# * <tt>:multiple</tt> - If set to true, the selection will allow multiple choices.
|
84
151
|
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
85
152
|
# * <tt>:include_blank</tt> - If set to true, an empty option will be created. If set to a string, the string will be used as the option's content and the value will be empty.
|
86
153
|
# * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something.
|
@@ -93,27 +160,27 @@ module ActionView
|
|
93
160
|
# select_tag "people", options_from_collection_for_select(@people, "id", "name", "1")
|
94
161
|
# # <select id="people" name="people"><option value="1" selected="selected">David</option></select>
|
95
162
|
#
|
96
|
-
# select_tag "people", "<option>David</option>"
|
163
|
+
# select_tag "people", raw("<option>David</option>")
|
97
164
|
# # => <select id="people" name="people"><option>David</option></select>
|
98
165
|
#
|
99
|
-
# select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>"
|
166
|
+
# select_tag "count", raw("<option>1</option><option>2</option><option>3</option><option>4</option>")
|
100
167
|
# # => <select id="count" name="count"><option>1</option><option>2</option>
|
101
168
|
# # <option>3</option><option>4</option></select>
|
102
169
|
#
|
103
|
-
# select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>"
|
170
|
+
# select_tag "colors", raw("<option>Red</option><option>Green</option><option>Blue</option>"), multiple: true
|
104
171
|
# # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option>
|
105
172
|
# # <option>Green</option><option>Blue</option></select>
|
106
173
|
#
|
107
|
-
# select_tag "locations", "<option>Home</option><option selected='selected'>Work</option><option>Out</option>"
|
174
|
+
# select_tag "locations", raw("<option>Home</option><option selected='selected'>Work</option><option>Out</option>")
|
108
175
|
# # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option>
|
109
176
|
# # <option>Out</option></select>
|
110
177
|
#
|
111
|
-
# select_tag "access", "<option>Read</option><option>Write</option>"
|
178
|
+
# select_tag "access", raw("<option>Read</option><option>Write</option>"), multiple: true, class: 'form_input', id: 'unique_id'
|
112
179
|
# # => <select class="form_input" id="unique_id" multiple="multiple" name="access[]"><option>Read</option>
|
113
180
|
# # <option>Write</option></select>
|
114
181
|
#
|
115
182
|
# select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: true
|
116
|
-
# # => <select id="people" name="people"><option value=""></option><option value="1">David</option></select>
|
183
|
+
# # => <select id="people" name="people"><option value="" label=" "></option><option value="1">David</option></select>
|
117
184
|
#
|
118
185
|
# select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: "All"
|
119
186
|
# # => <select id="people" name="people"><option value="">All</option><option value="1">David</option></select>
|
@@ -121,7 +188,7 @@ module ActionView
|
|
121
188
|
# select_tag "people", options_from_collection_for_select(@people, "id", "name"), prompt: "Select something"
|
122
189
|
# # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select>
|
123
190
|
#
|
124
|
-
# select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>"
|
191
|
+
# select_tag "destination", raw("<option>NYC</option><option>Paris</option><option>Rome</option>"), disabled: true
|
125
192
|
# # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
|
126
193
|
# # <option>Paris</option><option>Rome</option></select>
|
127
194
|
#
|
@@ -130,25 +197,28 @@ module ActionView
|
|
130
197
|
# # <option selected="selected">MasterCard</option></select>
|
131
198
|
def select_tag(name, option_tags = nil, options = {})
|
132
199
|
option_tags ||= ""
|
133
|
-
html_name = (options[:multiple] == true && !name.
|
200
|
+
html_name = (options[:multiple] == true && !name.end_with?("[]")) ? "#{name}[]" : name
|
134
201
|
|
135
202
|
if options.include?(:include_blank)
|
136
|
-
include_blank = options
|
203
|
+
include_blank = options[:include_blank]
|
204
|
+
options = options.except(:include_blank)
|
205
|
+
options_for_blank_options_tag = { value: "" }
|
137
206
|
|
138
207
|
if include_blank == true
|
139
|
-
include_blank =
|
208
|
+
include_blank = ""
|
209
|
+
options_for_blank_options_tag[:label] = " "
|
140
210
|
end
|
141
211
|
|
142
212
|
if include_blank
|
143
|
-
option_tags = content_tag(
|
213
|
+
option_tags = content_tag("option", include_blank, options_for_blank_options_tag).safe_concat(option_tags)
|
144
214
|
end
|
145
215
|
end
|
146
216
|
|
147
217
|
if prompt = options.delete(:prompt)
|
148
|
-
option_tags = content_tag(
|
218
|
+
option_tags = content_tag("option", prompt, value: "").safe_concat(option_tags)
|
149
219
|
end
|
150
220
|
|
151
|
-
content_tag
|
221
|
+
content_tag "select", option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
|
152
222
|
end
|
153
223
|
|
154
224
|
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
|
@@ -159,6 +229,8 @@ module ActionView
|
|
159
229
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
160
230
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
161
231
|
# * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
|
232
|
+
# If set to true, use the translation found in the current I18n locale
|
233
|
+
# (through helpers.placeholder.<modelname>.<attribute>).
|
162
234
|
# * Any other key creates standard HTML attributes for the tag.
|
163
235
|
#
|
164
236
|
# ==== Examples
|
@@ -222,16 +294,16 @@ module ActionView
|
|
222
294
|
#
|
223
295
|
# ==== Examples
|
224
296
|
# hidden_field_tag 'tags_list'
|
225
|
-
# # => <input
|
297
|
+
# # => <input type="hidden" name="tags_list" id="tags_list" autocomplete="off" />
|
226
298
|
#
|
227
299
|
# hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
|
228
|
-
# # => <input
|
300
|
+
# # => <input type="hidden" name="token" id="token" value="VUBJKB23UIVI1UU1VOBVI@" autocomplete="off" />
|
229
301
|
#
|
230
302
|
# hidden_field_tag 'collected_input', '', onchange: "alert('Input collected!')"
|
231
|
-
# # => <input
|
232
|
-
#
|
303
|
+
# # => <input type="hidden" name="collected_input" id="collected_input"
|
304
|
+
# value="" onchange="alert('Input collected!')" autocomplete="off" />
|
233
305
|
def hidden_field_tag(name, value = nil, options = {})
|
234
|
-
text_field_tag(name, value, options.merge(type: :hidden))
|
306
|
+
text_field_tag(name, value, options.merge(type: :hidden, autocomplete: "off"))
|
235
307
|
end
|
236
308
|
|
237
309
|
# Creates a file upload field. If you are using file uploads then you will also need
|
@@ -270,7 +342,7 @@ module ActionView
|
|
270
342
|
# file_field_tag 'file', accept: 'text/html', class: 'upload', value: 'index.html'
|
271
343
|
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
|
272
344
|
def file_field_tag(name, options = {})
|
273
|
-
text_field_tag(name, nil, options.merge(type: :file))
|
345
|
+
text_field_tag(name, nil, convert_direct_upload_option_to_url(options.merge(type: :file)))
|
274
346
|
end
|
275
347
|
|
276
348
|
# Creates a password field, a masked text field that will hide the users input behind a mask character.
|
@@ -383,14 +455,14 @@ module ActionView
|
|
383
455
|
# * Any other key creates standard HTML options for the tag.
|
384
456
|
#
|
385
457
|
# ==== Examples
|
386
|
-
# radio_button_tag '
|
387
|
-
# # => <input id="
|
458
|
+
# radio_button_tag 'favorite_color', 'maroon'
|
459
|
+
# # => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" />
|
388
460
|
#
|
389
461
|
# radio_button_tag 'receive_updates', 'no', true
|
390
462
|
# # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
|
391
463
|
#
|
392
464
|
# radio_button_tag 'time_slot', "3:00 p.m.", false, disabled: true
|
393
|
-
# # => <input disabled="disabled" id="
|
465
|
+
# # => <input disabled="disabled" id="time_slot_3:00_p.m." name="time_slot" type="radio" value="3:00 p.m." />
|
394
466
|
#
|
395
467
|
# radio_button_tag 'color', "green", true, class: "color_input"
|
396
468
|
# # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
|
@@ -407,49 +479,55 @@ module ActionView
|
|
407
479
|
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
|
408
480
|
# * Any other key creates standard HTML options for the tag.
|
409
481
|
#
|
410
|
-
# ==== Data attributes
|
411
|
-
#
|
412
|
-
# * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
|
413
|
-
# drivers will provide a prompt with the question specified. If the user accepts,
|
414
|
-
# the form is processed normally, otherwise no action is taken.
|
415
|
-
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
|
416
|
-
# disabled version of the submit button when the form is submitted. This feature is
|
417
|
-
# provided by the unobtrusive JavaScript driver.
|
418
|
-
#
|
419
482
|
# ==== Examples
|
420
483
|
# submit_tag
|
421
|
-
# # => <input name="commit" type="submit" value="Save changes" />
|
484
|
+
# # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
|
422
485
|
#
|
423
486
|
# submit_tag "Edit this article"
|
424
|
-
# # => <input name="commit" type="submit" value="Edit this article" />
|
487
|
+
# # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" />
|
425
488
|
#
|
426
489
|
# submit_tag "Save edits", disabled: true
|
427
|
-
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
|
428
|
-
#
|
429
|
-
# submit_tag "Complete sale", data: { disable_with: "Please wait..." }
|
430
|
-
# # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
|
490
|
+
# # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
|
431
491
|
#
|
432
492
|
# submit_tag nil, class: "form_submit"
|
433
493
|
# # => <input class="form_submit" name="commit" type="submit" />
|
434
494
|
#
|
435
495
|
# submit_tag "Edit", class: "edit_button"
|
436
|
-
# # => <input class="edit_button" name="commit" type="submit" value="Edit" />
|
496
|
+
# # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
|
497
|
+
#
|
498
|
+
# ==== Deprecated: Rails UJS attributes
|
499
|
+
#
|
500
|
+
# Prior to Rails 7, Rails shipped with the JavaScript library called @rails/ujs on by default. Following Rails 7,
|
501
|
+
# this library is no longer on by default. This library integrated with the following options:
|
502
|
+
#
|
503
|
+
# * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
|
504
|
+
# drivers will provide a prompt with the question specified. If the user accepts,
|
505
|
+
# the form is processed normally, otherwise no action is taken.
|
506
|
+
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
|
507
|
+
# disabled version of the submit button when the form is submitted. This feature is
|
508
|
+
# provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
|
509
|
+
# pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
|
510
|
+
#
|
511
|
+
# submit_tag "Complete sale", data: { disable_with: "Submitting..." }
|
512
|
+
# # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
|
437
513
|
#
|
438
514
|
# submit_tag "Save", data: { confirm: "Are you sure?" }
|
439
|
-
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
|
515
|
+
# # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
|
440
516
|
#
|
441
517
|
def submit_tag(value = "Save changes", options = {})
|
442
|
-
options = options.
|
443
|
-
|
444
|
-
|
518
|
+
options = options.deep_stringify_keys
|
519
|
+
tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
|
520
|
+
set_default_disable_with value, tag_options
|
521
|
+
tag :input, tag_options
|
445
522
|
end
|
446
523
|
|
447
524
|
# Creates a button element that defines a <tt>submit</tt> button,
|
448
|
-
# <tt>reset</tt>button or a generic button which can be used in
|
525
|
+
# <tt>reset</tt> button or a generic button which can be used in
|
449
526
|
# JavaScript, for example. You can use the button tag as a regular
|
450
527
|
# submit tag but it isn't supported in legacy browsers. However,
|
451
|
-
# the button tag
|
452
|
-
# so this helper will also accept a block.
|
528
|
+
# the button tag does allow for richer labels such as images and emphasis,
|
529
|
+
# so this helper will also accept a block. By default, it will create
|
530
|
+
# a button tag with type <tt>submit</tt>, if type is not given.
|
453
531
|
#
|
454
532
|
# ==== Options
|
455
533
|
# * <tt>:data</tt> - This option can be used to add custom data attributes.
|
@@ -457,21 +535,19 @@ module ActionView
|
|
457
535
|
# use this input.
|
458
536
|
# * Any other key creates standard HTML options for the tag.
|
459
537
|
#
|
460
|
-
# ==== Data attributes
|
461
|
-
#
|
462
|
-
# * <tt>confirm: 'question?'</tt> - If present, the
|
463
|
-
# unobtrusive JavaScript drivers will provide a prompt with
|
464
|
-
# the question specified. If the user accepts, the form is
|
465
|
-
# processed normally, otherwise no action is taken.
|
466
|
-
# * <tt>:disable_with</tt> - Value of this parameter will be
|
467
|
-
# used as the value for a disabled version of the submit
|
468
|
-
# button when the form is submitted. This feature is provided
|
469
|
-
# by the unobtrusive JavaScript driver.
|
470
|
-
#
|
471
538
|
# ==== Examples
|
472
539
|
# button_tag
|
473
540
|
# # => <button name="button" type="submit">Button</button>
|
474
541
|
#
|
542
|
+
# button_tag 'Reset', type: 'reset'
|
543
|
+
# # => <button name="button" type="reset">Reset</button>
|
544
|
+
#
|
545
|
+
# button_tag 'Button', type: 'button'
|
546
|
+
# # => <button name="button" type="button">Button</button>
|
547
|
+
#
|
548
|
+
# button_tag 'Reset', type: 'reset', disabled: true
|
549
|
+
# # => <button name="button" type="reset" disabled="disabled">Reset</button>
|
550
|
+
#
|
475
551
|
# button_tag(type: 'button') do
|
476
552
|
# content_tag(:strong, 'Ask me!')
|
477
553
|
# end
|
@@ -479,6 +555,23 @@ module ActionView
|
|
479
555
|
# # <strong>Ask me!</strong>
|
480
556
|
# # </button>
|
481
557
|
#
|
558
|
+
# ==== Deprecated: Rails UJS attributes
|
559
|
+
#
|
560
|
+
# Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
|
561
|
+
# this library is no longer on by default. This library integrated with the following options:
|
562
|
+
#
|
563
|
+
# * <tt>confirm: 'question?'</tt> - If present, the
|
564
|
+
# unobtrusive JavaScript drivers will provide a prompt with
|
565
|
+
# the question specified. If the user accepts, the form is
|
566
|
+
# processed normally, otherwise no action is taken.
|
567
|
+
# * <tt>:disable_with</tt> - Value of this parameter will be
|
568
|
+
# used as the value for a disabled version of the submit
|
569
|
+
# button when the form is submitted. This feature is provided
|
570
|
+
# by the unobtrusive JavaScript driver.
|
571
|
+
#
|
572
|
+
# button_tag "Save", data: { confirm: "Are you sure?" }
|
573
|
+
# # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
|
574
|
+
#
|
482
575
|
# button_tag "Checkout", data: { disable_with: "Please wait..." }
|
483
576
|
# # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
|
484
577
|
#
|
@@ -489,12 +582,12 @@ module ActionView
|
|
489
582
|
options ||= {}
|
490
583
|
end
|
491
584
|
|
492
|
-
options = {
|
585
|
+
options = { "name" => "button", "type" => "submit" }.merge!(options.stringify_keys)
|
493
586
|
|
494
587
|
if block_given?
|
495
588
|
content_tag :button, options, &block
|
496
589
|
else
|
497
|
-
content_tag :button, content_or_options ||
|
590
|
+
content_tag :button, content_or_options || "Button", options
|
498
591
|
end
|
499
592
|
end
|
500
593
|
|
@@ -515,22 +608,23 @@ module ActionView
|
|
515
608
|
#
|
516
609
|
# ==== Examples
|
517
610
|
# image_submit_tag("login.png")
|
518
|
-
# # => <input
|
611
|
+
# # => <input src="/assets/login.png" type="image" />
|
519
612
|
#
|
520
613
|
# image_submit_tag("purchase.png", disabled: true)
|
521
|
-
# # => <input
|
614
|
+
# # => <input disabled="disabled" src="/assets/purchase.png" type="image" />
|
522
615
|
#
|
523
616
|
# image_submit_tag("search.png", class: 'search_button', alt: 'Find')
|
524
|
-
# # => <input
|
617
|
+
# # => <input class="search_button" src="/assets/search.png" type="image" />
|
525
618
|
#
|
526
619
|
# image_submit_tag("agree.png", disabled: true, class: "agree_disagree_button")
|
527
|
-
# # => <input
|
620
|
+
# # => <input class="agree_disagree_button" disabled="disabled" src="/assets/agree.png" type="image" />
|
528
621
|
#
|
529
622
|
# image_submit_tag("save.png", data: { confirm: "Are you sure?" })
|
530
|
-
# # => <input
|
623
|
+
# # => <input src="/assets/save.png" data-confirm="Are you sure?" type="image" />
|
531
624
|
def image_submit_tag(source, options = {})
|
532
625
|
options = options.stringify_keys
|
533
|
-
|
626
|
+
src = path_to_image(source, skip_pipeline: options.delete("skip_pipeline"))
|
627
|
+
tag :input, { "type" => "image", "src" => src }.update(options)
|
534
628
|
end
|
535
629
|
|
536
630
|
# Creates a field set for grouping HTML form elements.
|
@@ -555,7 +649,7 @@ module ActionView
|
|
555
649
|
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
|
556
650
|
def field_set_tag(legend = nil, options = nil, &block)
|
557
651
|
output = tag(:fieldset, options, true)
|
558
|
-
output.safe_concat(content_tag(
|
652
|
+
output.safe_concat(content_tag("legend", legend)) unless legend.blank?
|
559
653
|
output.concat(capture(&block)) if block_given?
|
560
654
|
output.safe_concat("</fieldset>")
|
561
655
|
end
|
@@ -651,12 +745,13 @@ module ActionView
|
|
651
745
|
# * <tt>:min</tt> - The minimum acceptable value.
|
652
746
|
# * <tt>:max</tt> - The maximum acceptable value.
|
653
747
|
# * <tt>:step</tt> - The acceptable value granularity.
|
748
|
+
# * <tt>:include_seconds</tt> - Include seconds and ms in the output timestamp format (true by default).
|
654
749
|
# * Otherwise accepts the same options as text_field_tag.
|
655
750
|
def time_field_tag(name, value = nil, options = {})
|
656
751
|
text_field_tag(name, value, options.merge(type: :time))
|
657
752
|
end
|
658
753
|
|
659
|
-
# Creates a text field of type "datetime".
|
754
|
+
# Creates a text field of type "datetime-local".
|
660
755
|
#
|
661
756
|
# === Options
|
662
757
|
# * <tt>:min</tt> - The minimum acceptable value.
|
@@ -664,19 +759,10 @@ module ActionView
|
|
664
759
|
# * <tt>:step</tt> - The acceptable value granularity.
|
665
760
|
# * Otherwise accepts the same options as text_field_tag.
|
666
761
|
def datetime_field_tag(name, value = nil, options = {})
|
667
|
-
text_field_tag(name, value, options.merge(type:
|
762
|
+
text_field_tag(name, value, options.merge(type: "datetime-local"))
|
668
763
|
end
|
669
764
|
|
670
|
-
|
671
|
-
#
|
672
|
-
# === Options
|
673
|
-
# * <tt>:min</tt> - The minimum acceptable value.
|
674
|
-
# * <tt>:max</tt> - The maximum acceptable value.
|
675
|
-
# * <tt>:step</tt> - The acceptable value granularity.
|
676
|
-
# * Otherwise accepts the same options as text_field_tag.
|
677
|
-
def datetime_local_field_tag(name, value = nil, options = {})
|
678
|
-
text_field_tag(name, value, options.merge(type: 'datetime-local'))
|
679
|
-
end
|
765
|
+
alias datetime_local_field_tag datetime_field_tag
|
680
766
|
|
681
767
|
# Creates a text field of type "month".
|
682
768
|
#
|
@@ -776,10 +862,10 @@ module ActionView
|
|
776
862
|
# # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
|
777
863
|
#
|
778
864
|
# number_field_tag 'quantity', nil, min: 1, max: 10
|
779
|
-
# # => <input id="quantity" name="quantity" min="1" max="
|
865
|
+
# # => <input id="quantity" name="quantity" min="1" max="10" type="number" />
|
780
866
|
#
|
781
867
|
# number_field_tag 'quantity', nil, min: 1, max: 10, step: 2
|
782
|
-
# # => <input id="quantity" name="quantity" min="1" max="
|
868
|
+
# # => <input id="quantity" name="quantity" min="1" max="10" step="2" type="number" />
|
783
869
|
#
|
784
870
|
# number_field_tag 'quantity', '1', class: 'special_input', disabled: true
|
785
871
|
# # => <input disabled="disabled" class="special_input" id="quantity" name="quantity" type="number" value="1" />
|
@@ -806,7 +892,7 @@ module ActionView
|
|
806
892
|
# Use raw HTML to ensure the value is written as an HTML entity; it
|
807
893
|
# needs to be the right character regardless of which encoding the
|
808
894
|
# browser infers.
|
809
|
-
'<input name="utf8" type="hidden" value="✓" />'.html_safe
|
895
|
+
'<input name="utf8" type="hidden" value="✓" autocomplete="off" />'.html_safe
|
810
896
|
end
|
811
897
|
|
812
898
|
private
|
@@ -815,13 +901,17 @@ module ActionView
|
|
815
901
|
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
|
816
902
|
# The following URL is unescaped, this is just a hash of options, and it is the
|
817
903
|
# responsibility of the caller to escape all the values.
|
818
|
-
html_options["action"]
|
904
|
+
if url_for_options == false || html_options["action"] == false
|
905
|
+
html_options.delete("action")
|
906
|
+
else
|
907
|
+
html_options["action"] = url_for(url_for_options)
|
908
|
+
end
|
819
909
|
html_options["accept-charset"] = "UTF-8"
|
820
910
|
|
821
911
|
html_options["data-remote"] = true if html_options.delete("remote")
|
822
912
|
|
823
913
|
if html_options["data-remote"] &&
|
824
|
-
|
914
|
+
embed_authenticity_token_in_remote_forms == false &&
|
825
915
|
html_options["authenticity_token"].blank?
|
826
916
|
# The authenticity token is taken from the meta tag in this case
|
827
917
|
html_options["authenticity_token"] = false
|
@@ -835,21 +925,28 @@ module ActionView
|
|
835
925
|
|
836
926
|
def extra_tags_for_form(html_options)
|
837
927
|
authenticity_token = html_options.delete("authenticity_token")
|
838
|
-
method = html_options.delete("method").to_s
|
928
|
+
method = html_options.delete("method").to_s.downcase
|
839
929
|
|
840
|
-
method_tag =
|
841
|
-
|
930
|
+
method_tag = \
|
931
|
+
case method
|
932
|
+
when "get"
|
842
933
|
html_options["method"] = "get"
|
843
|
-
|
844
|
-
when
|
934
|
+
""
|
935
|
+
when "post", ""
|
845
936
|
html_options["method"] = "post"
|
846
|
-
token_tag(authenticity_token
|
937
|
+
token_tag(authenticity_token, form_options: {
|
938
|
+
action: html_options["action"],
|
939
|
+
method: "post"
|
940
|
+
})
|
847
941
|
else
|
848
942
|
html_options["method"] = "post"
|
849
|
-
method_tag(method) + token_tag(authenticity_token
|
850
|
-
|
943
|
+
method_tag(method) + token_tag(authenticity_token, form_options: {
|
944
|
+
action: html_options["action"],
|
945
|
+
method: method
|
946
|
+
})
|
947
|
+
end
|
851
948
|
|
852
|
-
if html_options.delete("enforce_utf8") {
|
949
|
+
if html_options.delete("enforce_utf8") { default_enforce_utf8 }
|
853
950
|
utf8_enforcer_tag + method_tag
|
854
951
|
else
|
855
952
|
method_tag
|
@@ -863,13 +960,35 @@ module ActionView
|
|
863
960
|
|
864
961
|
def form_tag_with_body(html_options, content)
|
865
962
|
output = form_tag_html(html_options)
|
866
|
-
output << content
|
963
|
+
output << content.to_s if content
|
867
964
|
output.safe_concat("</form>")
|
868
965
|
end
|
869
966
|
|
870
967
|
# see http://www.w3.org/TR/html4/types.html#type-name
|
871
968
|
def sanitize_to_id(name)
|
872
|
-
name.to_s.delete(
|
969
|
+
name.to_s.delete("]").tr("^-a-zA-Z0-9:.", "_")
|
970
|
+
end
|
971
|
+
|
972
|
+
def set_default_disable_with(value, tag_options)
|
973
|
+
data = tag_options.fetch("data", {})
|
974
|
+
|
975
|
+
if tag_options["data-disable-with"] == false || data["disable_with"] == false
|
976
|
+
data.delete("disable_with")
|
977
|
+
elsif ActionView::Base.automatically_disable_submit_tag
|
978
|
+
disable_with_text = tag_options["data-disable-with"]
|
979
|
+
disable_with_text ||= data["disable_with"]
|
980
|
+
disable_with_text ||= value.to_s.clone
|
981
|
+
tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
|
982
|
+
end
|
983
|
+
|
984
|
+
tag_options.delete("data-disable-with")
|
985
|
+
end
|
986
|
+
|
987
|
+
def convert_direct_upload_option_to_url(options)
|
988
|
+
if options.delete(:direct_upload) && respond_to?(:rails_direct_uploads_url)
|
989
|
+
options["data-direct-upload-url"] = rails_direct_uploads_url
|
990
|
+
end
|
991
|
+
options
|
873
992
|
end
|
874
993
|
end
|
875
994
|
end
|