actionview 6.1.4.4 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +93 -297
  3. data/MIT-LICENSE +1 -1
  4. data/lib/action_view/base.rb +3 -3
  5. data/lib/action_view/buffers.rb +2 -2
  6. data/lib/action_view/cache_expiry.rb +46 -32
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  8. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  9. data/lib/action_view/dependency_tracker.rb +6 -147
  10. data/lib/action_view/digestor.rb +7 -4
  11. data/lib/action_view/flows.rb +4 -4
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
  15. data/lib/action_view/helpers/asset_url_helper.rb +7 -7
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +51 -3
  18. data/lib/action_view/helpers/capture_helper.rb +2 -2
  19. data/lib/action_view/helpers/controller_helper.rb +2 -2
  20. data/lib/action_view/helpers/csp_helper.rb +1 -1
  21. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  22. data/lib/action_view/helpers/date_helper.rb +5 -5
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +72 -12
  25. data/lib/action_view/helpers/form_options_helper.rb +65 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +73 -30
  27. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  28. data/lib/action_view/helpers/number_helper.rb +3 -4
  29. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  30. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  31. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  32. data/lib/action_view/helpers/tag_helper.rb +17 -4
  33. data/lib/action_view/helpers/tags/base.rb +2 -14
  34. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  35. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  36. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  37. data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
  38. data/lib/action_view/helpers/tags.rb +3 -2
  39. data/lib/action_view/helpers/text_helper.rb +24 -13
  40. data/lib/action_view/helpers/translation_helper.rb +1 -2
  41. data/lib/action_view/helpers/url_helper.rb +110 -81
  42. data/lib/action_view/helpers.rb +25 -25
  43. data/lib/action_view/lookup_context.rb +33 -52
  44. data/lib/action_view/model_naming.rb +1 -1
  45. data/lib/action_view/path_set.rb +16 -22
  46. data/lib/action_view/railtie.rb +15 -2
  47. data/lib/action_view/render_parser.rb +188 -0
  48. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  49. data/lib/action_view/renderer/partial_renderer.rb +0 -34
  50. data/lib/action_view/renderer/renderer.rb +4 -4
  51. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  52. data/lib/action_view/renderer/template_renderer.rb +6 -2
  53. data/lib/action_view/rendering.rb +2 -2
  54. data/lib/action_view/ripper_ast_parser.rb +198 -0
  55. data/lib/action_view/routing_url_for.rb +1 -1
  56. data/lib/action_view/template/error.rb +108 -13
  57. data/lib/action_view/template/handlers/erb.rb +6 -0
  58. data/lib/action_view/template/handlers.rb +3 -3
  59. data/lib/action_view/template/html.rb +3 -3
  60. data/lib/action_view/template/inline.rb +3 -3
  61. data/lib/action_view/template/raw_file.rb +3 -3
  62. data/lib/action_view/template/resolver.rb +84 -311
  63. data/lib/action_view/template/text.rb +3 -3
  64. data/lib/action_view/template/types.rb +14 -12
  65. data/lib/action_view/template.rb +10 -1
  66. data/lib/action_view/template_details.rb +66 -0
  67. data/lib/action_view/template_path.rb +64 -0
  68. data/lib/action_view/test_case.rb +6 -2
  69. data/lib/action_view/testing/resolvers.rb +11 -12
  70. data/lib/action_view/unbound_template.rb +33 -7
  71. data/lib/action_view.rb +3 -4
  72. metadata +22 -15
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags # :nodoc:
6
+ class WeekdaySelect < Base # :nodoc:
7
+ def initialize(object_name, method_name, template_object, options, html_options)
8
+ @html_options = html_options
9
+
10
+ super(object_name, method_name, template_object, options)
11
+ end
12
+
13
+ def render
14
+ select_content_tag(
15
+ weekday_options_for_select(
16
+ value || @options[:selected],
17
+ index_as_value: @options.fetch(:index_as_value, false),
18
+ day_format: @options.fetch(:day_format, :day_names)
19
+ ),
20
+ @options,
21
+ @html_options
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- module Helpers #:nodoc:
5
- module Tags #:nodoc:
4
+ module Helpers # :nodoc:
5
+ module Tags # :nodoc:
6
6
  extend ActiveSupport::Autoload
7
7
 
8
8
  eager_autoload do
@@ -38,6 +38,7 @@ module ActionView
38
38
  autoload :TimeZoneSelect
39
39
  autoload :UrlField
40
40
  autoload :WeekField
41
+ autoload :WeekdaySelect
41
42
  end
42
43
  end
43
44
  end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/filters"
4
+ require "active_support/core_ext/string/access"
4
5
  require "active_support/core_ext/array/extract_options"
6
+ require "action_view/helpers/sanitize_helper"
7
+ require "action_view/helpers/tag_helper"
8
+ require "action_view/helpers/output_safety_helper"
5
9
 
6
10
  module ActionView
7
11
  # = Action View Text Helpers
8
- module Helpers #:nodoc:
12
+ module Helpers # :nodoc:
9
13
  # The TextHelper module provides a set of methods for filtering, formatting
10
14
  # and transforming strings, which can reduce the amount of inline Ruby code in
11
15
  # your views. These helper methods extend Action View making them callable
@@ -129,7 +133,7 @@ module ActionView
129
133
  #
130
134
  # highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
131
135
  # # => <a href="javascript:alert('no!')">ruby</a> on <mark>rails</mark>
132
- def highlight(text, phrases, options = {})
136
+ def highlight(text, phrases, options = {}, &block)
133
137
  text = sanitize(text) if options.fetch(:sanitize, true)
134
138
 
135
139
  if text.blank? || phrases.blank?
@@ -140,7 +144,7 @@ module ActionView
140
144
  end.join("|")
141
145
 
142
146
  if block_given?
143
- text.gsub(/(#{match})(?![^<]*?>)/i) { |found| yield found }
147
+ text.gsub(/(#{match})(?![^<]*?>)/i, &block)
144
148
  else
145
149
  highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
146
150
  text.gsub(/(#{match})(?![^<]*?>)/i, highlighter)
@@ -403,7 +407,7 @@ module ActionView
403
407
  cycle.reset if cycle
404
408
  end
405
409
 
406
- class Cycle #:nodoc:
410
+ class Cycle # :nodoc:
407
411
  attr_reader :values
408
412
 
409
413
  def initialize(first_value, *values)
@@ -467,18 +471,25 @@ module ActionView
467
471
  radius = options.fetch(:radius, 100)
468
472
  omission = options.fetch(:omission, "...")
469
473
 
470
- part = part.split(separator)
471
- part.delete("")
472
- affix = part.size > radius ? omission : ""
474
+ if separator != ""
475
+ part = part.split(separator)
476
+ part.delete("")
477
+ end
473
478
 
474
- part = if part_position == :first
475
- drop_index = [part.length - radius, 0].max
476
- part.drop(drop_index)
477
- else
478
- part.first(radius)
479
+ affix = part.length > radius ? omission : ""
480
+
481
+ part =
482
+ if part_position == :first
483
+ part.last(radius)
484
+ else
485
+ part.first(radius)
486
+ end
487
+
488
+ if separator != ""
489
+ part = part.join(separator)
479
490
  end
480
491
 
481
- return affix, part.join(separator)
492
+ return affix, part
482
493
  end
483
494
  end
484
495
  end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_view/helpers/tag_helper"
4
- require "active_support/core_ext/symbol/starts_ends_with"
5
4
 
6
5
  module ActionView
7
6
  # = Action View Translation Helpers
8
- module Helpers #:nodoc:
7
+ module Helpers # :nodoc:
9
8
  module TranslationHelper
10
9
  extend ActiveSupport::Concern
11
10
 
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/helpers/javascript_helper"
4
3
  require "active_support/core_ext/array/access"
5
4
  require "active_support/core_ext/hash/keys"
6
5
  require "active_support/core_ext/string/output_safety"
6
+ require "action_view/helpers/tag_helper"
7
7
 
8
8
  module ActionView
9
9
  # = Action View URL Helpers
10
- module Helpers #:nodoc:
10
+ module Helpers # :nodoc:
11
11
  # Provides a set of methods for making links and getting URLs that
12
12
  # depend on the routing subsystem (see ActionDispatch::Routing).
13
13
  # This allows you to use the same format for links in views
@@ -29,6 +29,8 @@ module ActionView
29
29
  end
30
30
  end
31
31
 
32
+ mattr_accessor :button_to_generates_button_tag, default: false
33
+
32
34
  # Basic implementation of url_for to allow use helpers without routes existence
33
35
  def url_for(options = nil) # :nodoc:
34
36
  case options
@@ -101,17 +103,8 @@ module ActionView
101
103
  # completion of the Ajax request and performing JavaScript operations once
102
104
  # they're complete
103
105
  #
104
- # ==== Data attributes
105
- #
106
- # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
107
- # driver to prompt with the question specified (in this case, the
108
- # resulting text would be <tt>question?</tt>. If the user accepts, the
109
- # link is processed normally, otherwise no action is taken.
110
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the
111
- # name for a disabled version of the link. This feature is provided by
112
- # the unobtrusive JavaScript driver.
113
- #
114
106
  # ==== Examples
107
+ #
115
108
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
116
109
  # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
117
110
  # your application on resources and use
@@ -184,15 +177,27 @@ module ActionView
184
177
  # link_to("Destroy", "http://www.example.com", method: :delete)
185
178
  # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
186
179
  #
187
- # You can also use custom data attributes using the <tt>:data</tt> option:
188
- #
189
- # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
190
- # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
191
- #
192
180
  # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
193
181
  #
194
182
  # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
195
183
  # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
184
+ #
185
+ # ==== Deprecated: Rails UJS attributes
186
+ #
187
+ # Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
188
+ # this library is no longer on by default. This library integrated with the following options:
189
+ #
190
+ # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
191
+ # driver to prompt with the question specified (in this case, the
192
+ # resulting text would be <tt>question?</tt>. If the user accepts, the
193
+ # link is processed normally, otherwise no action is taken.
194
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the
195
+ # name for a disabled version of the link. This feature is provided by
196
+ # the unobtrusive JavaScript driver.
197
+ #
198
+ # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
199
+ # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
200
+ #
196
201
  def link_to(name = nil, options = nil, html_options = nil, &block)
197
202
  html_options, options, name = options, name, block if block_given?
198
203
  options ||= {}
@@ -212,20 +217,24 @@ module ActionView
212
217
  # using the +link_to+ method with the <tt>:method</tt> modifier as described in
213
218
  # the +link_to+ documentation.
214
219
  #
215
- # By default, the generated form element has a class name of <tt>button_to</tt>
216
- # to allow styling of the form itself and its children. This can be changed
217
- # using the <tt>:form_class</tt> modifier within +html_options+. You can control
218
- # the form submission and input element behavior using +html_options+.
219
- # This method accepts the <tt>:method</tt> modifier described in the +link_to+ documentation.
220
- # If no <tt>:method</tt> modifier is given, it will default to performing a POST operation.
221
- # You can also disable the button by passing <tt>disabled: true</tt> in +html_options+.
222
- # If you are using RESTful routes, you can pass the <tt>:method</tt>
223
- # to change the HTTP verb used to submit the form.
220
+ # You can control the form and button behavior with +html_options+. Most
221
+ # values in +html_options+ are passed through to the button element. For
222
+ # example, passing a +:class+ option within +html_options+ will set the
223
+ # class attribute of the button element.
224
+ #
225
+ # The class attribute of the form element can be set by passing a
226
+ # +:form_class+ option within +html_options+. It defaults to
227
+ # <tt>"button_to"</tt> to allow styling of the form and its children.
228
+ #
229
+ # The form submits a POST request by default. You can specify a different
230
+ # HTTP verb via the +:method+ option within +html_options+.
224
231
  #
225
232
  # ==== Options
226
233
  # The +options+ hash accepts the same options as +url_for+.
227
234
  #
228
- # There are a few special +html_options+:
235
+ # Most values in +html_options+ are passed through to the button element,
236
+ # but there are a few special options:
237
+ #
229
238
  # * <tt>:method</tt> - \Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
230
239
  # <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
231
240
  # * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
@@ -250,12 +259,21 @@ module ActionView
250
259
  # ==== Examples
251
260
  # <%= button_to "New", action: "new" %>
252
261
  # # => "<form method="post" action="/controller/new" class="button_to">
253
- # # <input value="New" type="submit" />
262
+ # # <button type="submit">New</button>
263
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
254
264
  # # </form>"
255
265
  #
256
266
  # <%= button_to "New", new_article_path %>
257
267
  # # => "<form method="post" action="/articles/new" class="button_to">
258
- # # <input value="New" type="submit" />
268
+ # # <button type="submit">New</button>
269
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
270
+ # # </form>"
271
+ #
272
+ # <%= button_to "New", new_article_path, params: { time: Time.now } %>
273
+ # # => "<form method="post" action="/articles/new" class="button_to">
274
+ # # <button type="submit">New</button>
275
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
276
+ # # <input type="hidden" name="time" value="2021-04-08 14:06:09 -0500">
259
277
  # # </form>"
260
278
  #
261
279
  # <%= button_to [:make_happy, @user] do %>
@@ -265,35 +283,34 @@ module ActionView
265
283
  # # <button type="submit">
266
284
  # # Make happy <strong><%= @user.name %></strong>
267
285
  # # </button>
286
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
268
287
  # # </form>"
269
288
  #
270
289
  # <%= button_to "New", { action: "new" }, form_class: "new-thing" %>
271
290
  # # => "<form method="post" action="/controller/new" class="new-thing">
272
- # # <input value="New" type="submit" />
291
+ # # <button type="submit">New</button>
292
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
273
293
  # # </form>"
274
294
  #
275
- #
276
295
  # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
277
296
  # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
278
- # # <input value="Create" type="submit" />
297
+ # # <button type="submit">Create</button>
279
298
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
280
299
  # # </form>"
281
300
  #
282
- #
283
301
  # <%= button_to "Delete Image", { action: "delete", id: @image.id },
284
302
  # method: :delete, data: { confirm: "Are you sure?" } %>
285
303
  # # => "<form method="post" action="/images/delete/1" class="button_to">
286
304
  # # <input type="hidden" name="_method" value="delete" />
287
- # # <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
305
+ # # <button data-confirm='Are you sure?' type="submit">Delete Image</button>
288
306
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
289
307
  # # </form>"
290
308
  #
291
- #
292
309
  # <%= button_to('Destroy', 'http://www.example.com',
293
310
  # method: :delete, remote: true, data: { confirm: 'Are you sure?', disable_with: 'loading...' }) %>
294
311
  # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
295
312
  # # <input name='_method' value='delete' type='hidden' />
296
- # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
313
+ # # <button type='submit' data-disable-with='loading...' data-confirm='Are you sure?'>Destroy</button>
297
314
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
298
315
  # # </form>"
299
316
  # #
@@ -327,8 +344,8 @@ module ActionView
327
344
  html_options = convert_options_to_data_attributes(options, html_options)
328
345
  html_options["type"] = "submit"
329
346
 
330
- button = if block_given?
331
- content_tag("button", html_options, &block)
347
+ button = if block_given? || button_to_generates_button_tag
348
+ content_tag("button", name || url, html_options, &block)
332
349
  else
333
350
  html_options["value"] = name || url
334
351
  tag("input", html_options)
@@ -466,9 +483,9 @@ module ActionView
466
483
  # mail_to "me@domain.com", "My email"
467
484
  # # => <a href="mailto:me@domain.com">My email</a>
468
485
  #
469
- # mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
486
+ # mail_to "me@domain.com", cc: "ccaddress@domain.com",
470
487
  # subject: "This is an example email"
471
- # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
488
+ # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">me@domain.com</a>
472
489
  #
473
490
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
474
491
  #
@@ -479,7 +496,7 @@ module ActionView
479
496
  # <strong>Email me:</strong> <span>me@domain.com</span>
480
497
  # </a>
481
498
  def mail_to(email_address, name = nil, html_options = {}, &block)
482
- html_options, name = name, nil if block_given?
499
+ html_options, name = name, nil if name.is_a?(Hash)
483
500
  html_options = (html_options || {}).stringify_keys
484
501
 
485
502
  extras = %w{ cc bcc body subject reply_to }.map! { |item|
@@ -559,16 +576,14 @@ module ActionView
559
576
  request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
560
577
  request_uri = URI::DEFAULT_PARSER.unescape(request_uri).force_encoding(Encoding::BINARY)
561
578
 
562
- if url_string.start_with?("/") && url_string != "/"
563
- url_string.chomp!("/")
564
- request_uri.chomp!("/")
565
- end
566
-
567
579
  if %r{^\w+://}.match?(url_string)
568
- url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
569
- else
570
- url_string == request_uri
580
+ request_uri = +"#{request.protocol}#{request.host_with_port}#{request_uri}"
571
581
  end
582
+
583
+ remove_trailing_slash!(url_string)
584
+ remove_trailing_slash!(request_uri)
585
+
586
+ url_string == request_uri
572
587
  end
573
588
 
574
589
  if RUBY_VERSION.start_with?("2.7")
@@ -584,29 +599,37 @@ module ActionView
584
599
  end
585
600
  end
586
601
 
587
- # Creates an SMS anchor link tag to the specified +phone_number+, which is
588
- # also used as the name of the link unless +name+ is specified. Additional
589
- # HTML attributes for the link can be passed in +html_options+.
602
+ # Creates an SMS anchor link tag to the specified +phone_number+. When the
603
+ # link is clicked, the default SMS messaging app is opened ready to send a
604
+ # message to the linked phone number. If the +body+ option is specified,
605
+ # the contents of the message will be preset to +body+.
590
606
  #
591
- # When clicked, an SMS message is prepopulated with the passed phone number
592
- # and optional +body+ value.
607
+ # If +name+ is not specified, +phone_number+ will be used as the name of
608
+ # the link.
593
609
  #
594
- # +sms_to+ has a +body+ option for customizing the SMS message itself by
595
- # passing special keys to +html_options+.
610
+ # A +country_code+ option is supported, which prepends a plus sign and the
611
+ # given country code to the linked phone number. For example,
612
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
613
+ # phone number.
614
+ #
615
+ # Additional HTML attributes for the link can be passed via +html_options+.
596
616
  #
597
617
  # ==== Options
618
+ # * <tt>:country_code</tt> - Prepend the country code to the phone number.
598
619
  # * <tt>:body</tt> - Preset the body of the message.
599
620
  #
600
621
  # ==== Examples
601
622
  # sms_to "5155555785"
602
623
  # # => <a href="sms:5155555785;">5155555785</a>
603
624
  #
625
+ # sms_to "5155555785", country_code: "01"
626
+ # # => <a href="sms:+015155555785;">5155555785</a>
627
+ #
604
628
  # sms_to "5155555785", "Text me"
605
629
  # # => <a href="sms:5155555785;">Text me</a>
606
630
  #
607
- # sms_to "5155555785", "Text me",
608
- # body: "Hello Jim I have a question about your product."
609
- # # => <a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
631
+ # sms_to "5155555785", body: "I have a question about your product."
632
+ # # => <a href="sms:5155555785;?body=I%20have%20a%20question%20about%20your%20product">5155555785</a>
610
633
  #
611
634
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
612
635
  #
@@ -617,46 +640,47 @@ module ActionView
617
640
  # <strong>Text me:</strong>
618
641
  # </a>
619
642
  def sms_to(phone_number, name = nil, html_options = {}, &block)
620
- html_options, name = name, nil if block_given?
643
+ html_options, name = name, nil if name.is_a?(Hash)
621
644
  html_options = (html_options || {}).stringify_keys
622
645
 
623
- extras = %w{ body }.map! { |item|
624
- option = html_options.delete(item).presence || next
625
- "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
626
- }.compact
627
- extras = extras.empty? ? "" : "?&" + extras.join("&")
646
+ country_code = html_options.delete("country_code").presence
647
+ country_code = country_code ? "+#{ERB::Util.url_encode(country_code)}" : ""
648
+
649
+ body = html_options.delete("body").presence
650
+ body = body ? "?&body=#{ERB::Util.url_encode(body)}" : ""
628
651
 
629
652
  encoded_phone_number = ERB::Util.url_encode(phone_number)
630
- html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
653
+ html_options["href"] = "sms:#{country_code}#{encoded_phone_number};#{body}"
631
654
 
632
655
  content_tag("a", name || phone_number, html_options, &block)
633
656
  end
634
657
 
635
- # Creates a TEL anchor link tag to the specified +phone_number+, which is
636
- # also used as the name of the link unless +name+ is specified. Additional
637
- # HTML attributes for the link can be passed in +html_options+.
658
+ # Creates a TEL anchor link tag to the specified +phone_number+. When the
659
+ # link is clicked, the default app to make phone calls is opened and
660
+ # prepopulated with the phone number.
661
+ #
662
+ # If +name+ is not specified, +phone_number+ will be used as the name of
663
+ # the link.
638
664
  #
639
- # When clicked, the default app to make calls is opened, and it
640
- # is prepopulated with the passed phone number and optional
641
- # +country_code+ value.
665
+ # A +country_code+ option is supported, which prepends a plus sign and the
666
+ # given country code to the linked phone number. For example,
667
+ # <tt>country_code: "01"</tt> will prepend <tt>+01</tt> to the linked
668
+ # phone number.
642
669
  #
643
- # +phone_to+ has an optional +country_code+ option which automatically adds the country
644
- # code as well as the + sign in the phone numer that gets prepopulated,
645
- # for example if +country_code: "01"+ +\+01+ will be prepended to the
646
- # phone numer, by passing special keys to +html_options+.
670
+ # Additional HTML attributes for the link can be passed via +html_options+.
647
671
  #
648
672
  # ==== Options
649
- # * <tt>:country_code</tt> - Prepends the country code to the number
673
+ # * <tt>:country_code</tt> - Prepends the country code to the phone number
650
674
  #
651
675
  # ==== Examples
652
676
  # phone_to "1234567890"
653
677
  # # => <a href="tel:1234567890">1234567890</a>
654
678
  #
655
679
  # phone_to "1234567890", "Phone me"
656
- # # => <a href="tel:134567890">Phone me</a>
680
+ # # => <a href="tel:1234567890">Phone me</a>
657
681
  #
658
- # phone_to "1234567890", "Phone me", country_code: "01"
659
- # # => <a href="tel:+015155555785">Phone me</a>
682
+ # phone_to "1234567890", country_code: "01"
683
+ # # => <a href="tel:+011234567890">1234567890</a>
660
684
  #
661
685
  # You can use a block as well if your link target is hard to fit into the name parameter. \ERB example:
662
686
  #
@@ -667,7 +691,7 @@ module ActionView
667
691
  # <strong>Phone me:</strong>
668
692
  # </a>
669
693
  def phone_to(phone_number, name = nil, html_options = {}, &block)
670
- html_options, name = name, nil if block_given?
694
+ html_options, name = name, nil if name.is_a?(Hash)
671
695
  html_options = (html_options || {}).stringify_keys
672
696
 
673
697
  country_code = html_options.delete("country_code").presence
@@ -779,6 +803,11 @@ module ActionView
779
803
 
780
804
  params.sort_by { |pair| pair[:name] }
781
805
  end
806
+
807
+ def remove_trailing_slash!(url_string)
808
+ trailing_index = (url_string.index("?") || 0) - 1
809
+ url_string[trailing_index] = "" if url_string[trailing_index] == "/"
810
+ end
782
811
  end
783
812
  end
784
813
  end
@@ -1,34 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/benchmarkable"
4
+ require "action_view/helpers/capture_helper"
5
+ require "action_view/helpers/output_safety_helper"
6
+ require "action_view/helpers/tag_helper"
7
+ require "action_view/helpers/url_helper"
8
+ require "action_view/helpers/sanitize_helper"
9
+ require "action_view/helpers/text_helper"
10
+ require "action_view/helpers/active_model_helper"
11
+ require "action_view/helpers/asset_tag_helper"
12
+ require "action_view/helpers/asset_url_helper"
13
+ require "action_view/helpers/atom_feed_helper"
14
+ require "action_view/helpers/cache_helper"
15
+ require "action_view/helpers/controller_helper"
16
+ require "action_view/helpers/csp_helper"
17
+ require "action_view/helpers/csrf_helper"
18
+ require "action_view/helpers/date_helper"
19
+ require "action_view/helpers/debug_helper"
20
+ require "action_view/helpers/form_tag_helper"
21
+ require "action_view/helpers/form_helper"
22
+ require "action_view/helpers/form_options_helper"
23
+ require "action_view/helpers/javascript_helper"
24
+ require "action_view/helpers/number_helper"
25
+ require "action_view/helpers/rendering_helper"
26
+ require "action_view/helpers/translation_helper"
4
27
 
5
- module ActionView #:nodoc:
6
- module Helpers #:nodoc:
28
+ module ActionView # :nodoc:
29
+ module Helpers # :nodoc:
7
30
  extend ActiveSupport::Autoload
8
31
 
9
- autoload :ActiveModelHelper
10
- autoload :AssetTagHelper
11
- autoload :AssetUrlHelper
12
- autoload :AtomFeedHelper
13
- autoload :CacheHelper
14
- autoload :CaptureHelper
15
- autoload :ControllerHelper
16
- autoload :CspHelper
17
- autoload :CsrfHelper
18
- autoload :DateHelper
19
- autoload :DebugHelper
20
- autoload :FormHelper
21
- autoload :FormOptionsHelper
22
- autoload :FormTagHelper
23
- autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
24
- autoload :NumberHelper
25
- autoload :OutputSafetyHelper
26
- autoload :RenderingHelper
27
- autoload :SanitizeHelper
28
- autoload :TagHelper
29
- autoload :TextHelper
30
- autoload :TranslationHelper
31
- autoload :UrlHelper
32
32
  autoload :Tags
33
33
 
34
34
  def self.eager_load!