actionview 6.0.0

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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +271 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +40 -0
  5. data/lib/action_view.rb +98 -0
  6. data/lib/action_view/base.rb +312 -0
  7. data/lib/action_view/buffers.rb +67 -0
  8. data/lib/action_view/cache_expiry.rb +54 -0
  9. data/lib/action_view/context.rb +32 -0
  10. data/lib/action_view/dependency_tracker.rb +175 -0
  11. data/lib/action_view/digestor.rb +126 -0
  12. data/lib/action_view/flows.rb +76 -0
  13. data/lib/action_view/gem_version.rb +17 -0
  14. data/lib/action_view/helpers.rb +66 -0
  15. data/lib/action_view/helpers/active_model_helper.rb +55 -0
  16. data/lib/action_view/helpers/asset_tag_helper.rb +488 -0
  17. data/lib/action_view/helpers/asset_url_helper.rb +470 -0
  18. data/lib/action_view/helpers/atom_feed_helper.rb +205 -0
  19. data/lib/action_view/helpers/cache_helper.rb +271 -0
  20. data/lib/action_view/helpers/capture_helper.rb +216 -0
  21. data/lib/action_view/helpers/controller_helper.rb +36 -0
  22. data/lib/action_view/helpers/csp_helper.rb +26 -0
  23. data/lib/action_view/helpers/csrf_helper.rb +35 -0
  24. data/lib/action_view/helpers/date_helper.rb +1200 -0
  25. data/lib/action_view/helpers/debug_helper.rb +36 -0
  26. data/lib/action_view/helpers/form_helper.rb +2569 -0
  27. data/lib/action_view/helpers/form_options_helper.rb +896 -0
  28. data/lib/action_view/helpers/form_tag_helper.rb +920 -0
  29. data/lib/action_view/helpers/javascript_helper.rb +95 -0
  30. data/lib/action_view/helpers/number_helper.rb +456 -0
  31. data/lib/action_view/helpers/output_safety_helper.rb +70 -0
  32. data/lib/action_view/helpers/rendering_helper.rb +101 -0
  33. data/lib/action_view/helpers/sanitize_helper.rb +171 -0
  34. data/lib/action_view/helpers/tag_helper.rb +314 -0
  35. data/lib/action_view/helpers/tags.rb +44 -0
  36. data/lib/action_view/helpers/tags/base.rb +196 -0
  37. data/lib/action_view/helpers/tags/check_box.rb +66 -0
  38. data/lib/action_view/helpers/tags/checkable.rb +18 -0
  39. data/lib/action_view/helpers/tags/collection_check_boxes.rb +36 -0
  40. data/lib/action_view/helpers/tags/collection_helpers.rb +119 -0
  41. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +31 -0
  42. data/lib/action_view/helpers/tags/collection_select.rb +30 -0
  43. data/lib/action_view/helpers/tags/color_field.rb +27 -0
  44. data/lib/action_view/helpers/tags/date_field.rb +15 -0
  45. data/lib/action_view/helpers/tags/date_select.rb +74 -0
  46. data/lib/action_view/helpers/tags/datetime_field.rb +32 -0
  47. data/lib/action_view/helpers/tags/datetime_local_field.rb +21 -0
  48. data/lib/action_view/helpers/tags/datetime_select.rb +10 -0
  49. data/lib/action_view/helpers/tags/email_field.rb +10 -0
  50. data/lib/action_view/helpers/tags/file_field.rb +10 -0
  51. data/lib/action_view/helpers/tags/grouped_collection_select.rb +31 -0
  52. data/lib/action_view/helpers/tags/hidden_field.rb +10 -0
  53. data/lib/action_view/helpers/tags/label.rb +81 -0
  54. data/lib/action_view/helpers/tags/month_field.rb +15 -0
  55. data/lib/action_view/helpers/tags/number_field.rb +20 -0
  56. data/lib/action_view/helpers/tags/password_field.rb +14 -0
  57. data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
  58. data/lib/action_view/helpers/tags/radio_button.rb +33 -0
  59. data/lib/action_view/helpers/tags/range_field.rb +10 -0
  60. data/lib/action_view/helpers/tags/search_field.rb +27 -0
  61. data/lib/action_view/helpers/tags/select.rb +43 -0
  62. data/lib/action_view/helpers/tags/tel_field.rb +10 -0
  63. data/lib/action_view/helpers/tags/text_area.rb +24 -0
  64. data/lib/action_view/helpers/tags/text_field.rb +34 -0
  65. data/lib/action_view/helpers/tags/time_field.rb +15 -0
  66. data/lib/action_view/helpers/tags/time_select.rb +10 -0
  67. data/lib/action_view/helpers/tags/time_zone_select.rb +22 -0
  68. data/lib/action_view/helpers/tags/translator.rb +39 -0
  69. data/lib/action_view/helpers/tags/url_field.rb +10 -0
  70. data/lib/action_view/helpers/tags/week_field.rb +15 -0
  71. data/lib/action_view/helpers/text_helper.rb +486 -0
  72. data/lib/action_view/helpers/translation_helper.rb +145 -0
  73. data/lib/action_view/helpers/url_helper.rb +676 -0
  74. data/lib/action_view/layouts.rb +433 -0
  75. data/lib/action_view/locale/en.yml +56 -0
  76. data/lib/action_view/log_subscriber.rb +96 -0
  77. data/lib/action_view/lookup_context.rb +316 -0
  78. data/lib/action_view/model_naming.rb +14 -0
  79. data/lib/action_view/path_set.rb +95 -0
  80. data/lib/action_view/railtie.rb +105 -0
  81. data/lib/action_view/record_identifier.rb +112 -0
  82. data/lib/action_view/renderer/abstract_renderer.rb +108 -0
  83. data/lib/action_view/renderer/partial_renderer.rb +563 -0
  84. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  85. data/lib/action_view/renderer/renderer.rb +68 -0
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +105 -0
  87. data/lib/action_view/renderer/template_renderer.rb +108 -0
  88. data/lib/action_view/rendering.rb +171 -0
  89. data/lib/action_view/routing_url_for.rb +146 -0
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template.rb +393 -0
  92. data/lib/action_view/template/error.rb +161 -0
  93. data/lib/action_view/template/handlers.rb +92 -0
  94. data/lib/action_view/template/handlers/builder.rb +25 -0
  95. data/lib/action_view/template/handlers/erb.rb +84 -0
  96. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  97. data/lib/action_view/template/handlers/html.rb +11 -0
  98. data/lib/action_view/template/handlers/raw.rb +11 -0
  99. data/lib/action_view/template/html.rb +43 -0
  100. data/lib/action_view/template/inline.rb +22 -0
  101. data/lib/action_view/template/raw_file.rb +28 -0
  102. data/lib/action_view/template/resolver.rb +394 -0
  103. data/lib/action_view/template/sources.rb +13 -0
  104. data/lib/action_view/template/sources/file.rb +17 -0
  105. data/lib/action_view/template/text.rb +35 -0
  106. data/lib/action_view/template/types.rb +57 -0
  107. data/lib/action_view/test_case.rb +300 -0
  108. data/lib/action_view/testing/resolvers.rb +67 -0
  109. data/lib/action_view/unbound_template.rb +32 -0
  110. data/lib/action_view/version.rb +10 -0
  111. data/lib/action_view/view_paths.rb +129 -0
  112. data/lib/assets/compiled/rails-ujs.js +746 -0
  113. metadata +260 -0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers #:nodoc:
5
+ module Tags #:nodoc:
6
+ extend ActiveSupport::Autoload
7
+
8
+ eager_autoload do
9
+ autoload :Base
10
+ autoload :Translator
11
+ autoload :CheckBox
12
+ autoload :CollectionCheckBoxes
13
+ autoload :CollectionRadioButtons
14
+ autoload :CollectionSelect
15
+ autoload :ColorField
16
+ autoload :DateField
17
+ autoload :DateSelect
18
+ autoload :DatetimeField
19
+ autoload :DatetimeLocalField
20
+ autoload :DatetimeSelect
21
+ autoload :EmailField
22
+ autoload :FileField
23
+ autoload :GroupedCollectionSelect
24
+ autoload :HiddenField
25
+ autoload :Label
26
+ autoload :MonthField
27
+ autoload :NumberField
28
+ autoload :PasswordField
29
+ autoload :RadioButton
30
+ autoload :RangeField
31
+ autoload :SearchField
32
+ autoload :Select
33
+ autoload :TelField
34
+ autoload :TextArea
35
+ autoload :TextField
36
+ autoload :TimeField
37
+ autoload :TimeSelect
38
+ autoload :TimeZoneSelect
39
+ autoload :UrlField
40
+ autoload :WeekField
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags # :nodoc:
6
+ class Base # :nodoc:
7
+ include Helpers::ActiveModelInstanceTag, Helpers::TagHelper, Helpers::FormTagHelper
8
+ include FormOptionsHelper
9
+
10
+ attr_reader :object
11
+
12
+ def initialize(object_name, method_name, template_object, options = {})
13
+ @object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
14
+ @template_object = template_object
15
+
16
+ @object_name.sub!(/\[\]$/, "") || @object_name.sub!(/\[\]\]$/, "]")
17
+ @object = retrieve_object(options.delete(:object))
18
+ @skip_default_ids = options.delete(:skip_default_ids)
19
+ @allow_method_names_outside_object = options.delete(:allow_method_names_outside_object)
20
+ @options = options
21
+
22
+ if Regexp.last_match
23
+ @generate_indexed_names = true
24
+ @auto_index = retrieve_autoindex(Regexp.last_match.pre_match)
25
+ else
26
+ @generate_indexed_names = false
27
+ @auto_index = nil
28
+ end
29
+ end
30
+
31
+ # This is what child classes implement.
32
+ def render
33
+ raise NotImplementedError, "Subclasses must implement a render method"
34
+ end
35
+
36
+ private
37
+
38
+ def value
39
+ if @allow_method_names_outside_object
40
+ object.public_send @method_name if object && object.respond_to?(@method_name)
41
+ else
42
+ object.public_send @method_name if object
43
+ end
44
+ end
45
+
46
+ def value_before_type_cast
47
+ unless object.nil?
48
+ method_before_type_cast = @method_name + "_before_type_cast"
49
+
50
+ if value_came_from_user? && object.respond_to?(method_before_type_cast)
51
+ object.public_send(method_before_type_cast)
52
+ else
53
+ value
54
+ end
55
+ end
56
+ end
57
+
58
+ def value_came_from_user?
59
+ method_name = "#{@method_name}_came_from_user?"
60
+ !object.respond_to?(method_name) || object.public_send(method_name)
61
+ end
62
+
63
+ def retrieve_object(object)
64
+ if object
65
+ object
66
+ elsif @template_object.instance_variable_defined?("@#{@object_name}")
67
+ @template_object.instance_variable_get("@#{@object_name}")
68
+ end
69
+ rescue NameError
70
+ # As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil.
71
+ nil
72
+ end
73
+
74
+ def retrieve_autoindex(pre_match)
75
+ object = self.object || @template_object.instance_variable_get("@#{pre_match}")
76
+ if object && object.respond_to?(:to_param)
77
+ object.to_param
78
+ else
79
+ raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
80
+ end
81
+ end
82
+
83
+ def add_default_name_and_id_for_value(tag_value, options)
84
+ if tag_value.nil?
85
+ add_default_name_and_id(options)
86
+ else
87
+ specified_id = options["id"]
88
+ add_default_name_and_id(options)
89
+
90
+ if specified_id.blank? && options["id"].present?
91
+ options["id"] += "_#{sanitized_value(tag_value)}"
92
+ end
93
+ end
94
+ end
95
+
96
+ def add_default_name_and_id(options)
97
+ index = name_and_id_index(options)
98
+ options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
99
+
100
+ if generate_ids?
101
+ options["id"] = options.fetch("id") { tag_id(index) }
102
+ if namespace = options.delete("namespace")
103
+ options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
104
+ end
105
+ end
106
+ end
107
+
108
+ def tag_name(multiple = false, index = nil)
109
+ # a little duplication to construct less strings
110
+ case
111
+ when @object_name.empty?
112
+ "#{sanitized_method_name}#{multiple ? "[]" : ""}"
113
+ when index
114
+ "#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
115
+ else
116
+ "#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
117
+ end
118
+ end
119
+
120
+ def tag_id(index = nil)
121
+ # a little duplication to construct less strings
122
+ case
123
+ when @object_name.empty?
124
+ sanitized_method_name.dup
125
+ when index
126
+ "#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
127
+ else
128
+ "#{sanitized_object_name}_#{sanitized_method_name}"
129
+ end
130
+ end
131
+
132
+ def sanitized_object_name
133
+ @sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
134
+ end
135
+
136
+ def sanitized_method_name
137
+ @sanitized_method_name ||= @method_name.sub(/\?$/, "")
138
+ end
139
+
140
+ def sanitized_value(value)
141
+ value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
142
+ end
143
+
144
+ def select_content_tag(option_tags, options, html_options)
145
+ html_options = html_options.stringify_keys
146
+ add_default_name_and_id(html_options)
147
+
148
+ if placeholder_required?(html_options)
149
+ raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
150
+ options[:include_blank] ||= true unless options[:prompt]
151
+ end
152
+
153
+ value = options.fetch(:selected) { value() }
154
+ select = content_tag("select", add_options(option_tags, options, value), html_options)
155
+
156
+ if html_options["multiple"] && options.fetch(:include_hidden, true)
157
+ tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select
158
+ else
159
+ select
160
+ end
161
+ end
162
+
163
+ def placeholder_required?(html_options)
164
+ # See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
165
+ html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
166
+ end
167
+
168
+ def add_options(option_tags, options, value = nil)
169
+ if options[:include_blank]
170
+ option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags
171
+ end
172
+ if value.blank? && options[:prompt]
173
+ tag_options = { value: "" }.tap do |prompt_opts|
174
+ prompt_opts[:disabled] = true if options[:disabled] == ""
175
+ prompt_opts[:selected] = true if options[:selected] == ""
176
+ end
177
+ option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
178
+ end
179
+ option_tags
180
+ end
181
+
182
+ def name_and_id_index(options)
183
+ if options.key?("index")
184
+ options.delete("index") || ""
185
+ elsif @generate_indexed_names
186
+ @auto_index || ""
187
+ end
188
+ end
189
+
190
+ def generate_ids?
191
+ !@skip_default_ids
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view/helpers/tags/checkable"
4
+
5
+ module ActionView
6
+ module Helpers
7
+ module Tags # :nodoc:
8
+ class CheckBox < Base #:nodoc:
9
+ include Checkable
10
+
11
+ def initialize(object_name, method_name, template_object, checked_value, unchecked_value, options)
12
+ @checked_value = checked_value
13
+ @unchecked_value = unchecked_value
14
+ super(object_name, method_name, template_object, options)
15
+ end
16
+
17
+ def render
18
+ options = @options.stringify_keys
19
+ options["type"] = "checkbox"
20
+ options["value"] = @checked_value
21
+ options["checked"] = "checked" if input_checked?(options)
22
+
23
+ if options["multiple"]
24
+ add_default_name_and_id_for_value(@checked_value, options)
25
+ options.delete("multiple")
26
+ else
27
+ add_default_name_and_id(options)
28
+ end
29
+
30
+ include_hidden = options.delete("include_hidden") { true }
31
+ checkbox = tag("input", options)
32
+
33
+ if include_hidden
34
+ hidden = hidden_field_for_checkbox(options)
35
+ hidden + checkbox
36
+ else
37
+ checkbox
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def checked?(value)
44
+ case value
45
+ when TrueClass, FalseClass
46
+ value == !!@checked_value
47
+ when NilClass
48
+ false
49
+ when String
50
+ value == @checked_value
51
+ else
52
+ if value.respond_to?(:include?)
53
+ value.include?(@checked_value)
54
+ else
55
+ value.to_i == @checked_value.to_i
56
+ end
57
+ end
58
+ end
59
+
60
+ def hidden_field_for_checkbox(options)
61
+ @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags # :nodoc:
6
+ module Checkable # :nodoc:
7
+ def input_checked?(options)
8
+ if options.has_key?("checked")
9
+ checked = options.delete "checked"
10
+ checked == true || checked == "checked"
11
+ else
12
+ checked?(value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view/helpers/tags/collection_helpers"
4
+
5
+ module ActionView
6
+ module Helpers
7
+ module Tags # :nodoc:
8
+ class CollectionCheckBoxes < Base # :nodoc:
9
+ include CollectionHelpers
10
+
11
+ class CheckBoxBuilder < Builder # :nodoc:
12
+ def check_box(extra_html_options = {})
13
+ html_options = extra_html_options.merge(@input_html_options)
14
+ html_options[:multiple] = true
15
+ html_options[:skip_default_ids] = false
16
+ @template_object.check_box(@object_name, @method_name, html_options, @value, nil)
17
+ end
18
+ end
19
+
20
+ def render(&block)
21
+ render_collection_for(CheckBoxBuilder, &block)
22
+ end
23
+
24
+ private
25
+
26
+ def render_component(builder)
27
+ builder.check_box + builder.label
28
+ end
29
+
30
+ def hidden_field_name
31
+ "#{super}[]"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags # :nodoc:
6
+ module CollectionHelpers # :nodoc:
7
+ class Builder # :nodoc:
8
+ attr_reader :object, :text, :value
9
+
10
+ def initialize(template_object, object_name, method_name, object,
11
+ sanitized_attribute_name, text, value, input_html_options)
12
+ @template_object = template_object
13
+ @object_name = object_name
14
+ @method_name = method_name
15
+ @object = object
16
+ @sanitized_attribute_name = sanitized_attribute_name
17
+ @text = text
18
+ @value = value
19
+ @input_html_options = input_html_options
20
+ end
21
+
22
+ def label(label_html_options = {}, &block)
23
+ html_options = @input_html_options.slice(:index, :namespace).merge(label_html_options)
24
+ html_options[:for] ||= @input_html_options[:id] if @input_html_options[:id]
25
+
26
+ @template_object.label(@object_name, @sanitized_attribute_name, @text, html_options, &block)
27
+ end
28
+ end
29
+
30
+ def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
31
+ @collection = collection
32
+ @value_method = value_method
33
+ @text_method = text_method
34
+ @html_options = html_options
35
+
36
+ super(object_name, method_name, template_object, options)
37
+ end
38
+
39
+ private
40
+
41
+ def instantiate_builder(builder_class, item, value, text, html_options)
42
+ builder_class.new(@template_object, @object_name, @method_name, item,
43
+ sanitize_attribute_name(value), text, value, html_options)
44
+ end
45
+
46
+ # Generate default options for collection helpers, such as :checked and
47
+ # :disabled.
48
+ def default_html_options_for_collection(item, value)
49
+ html_options = @html_options.dup
50
+
51
+ [:checked, :selected, :disabled, :readonly].each do |option|
52
+ current_value = @options[option]
53
+ next if current_value.nil?
54
+
55
+ accept = if current_value.respond_to?(:call)
56
+ current_value.call(item)
57
+ else
58
+ Array(current_value).map(&:to_s).include?(value.to_s)
59
+ end
60
+
61
+ if accept
62
+ html_options[option] = true
63
+ elsif option == :checked
64
+ html_options[option] = false
65
+ end
66
+ end
67
+
68
+ html_options[:object] = @object
69
+ html_options
70
+ end
71
+
72
+ def sanitize_attribute_name(value)
73
+ "#{sanitized_method_name}_#{sanitized_value(value)}"
74
+ end
75
+
76
+ def render_collection
77
+ @collection.map do |item|
78
+ value = value_for_collection(item, @value_method)
79
+ text = value_for_collection(item, @text_method)
80
+ default_html_options = default_html_options_for_collection(item, value)
81
+ additional_html_options = option_html_attributes(item)
82
+
83
+ yield item, value, text, default_html_options.merge(additional_html_options)
84
+ end.join.html_safe
85
+ end
86
+
87
+ def render_collection_for(builder_class, &block)
88
+ options = @options.stringify_keys
89
+ rendered_collection = render_collection do |item, value, text, default_html_options|
90
+ builder = instantiate_builder(builder_class, item, value, text, default_html_options)
91
+
92
+ if block_given?
93
+ @template_object.capture(builder, &block)
94
+ else
95
+ render_component(builder)
96
+ end
97
+ end
98
+
99
+ # Prepend a hidden field to make sure something will be sent back to the
100
+ # server if all radio buttons are unchecked.
101
+ if options.fetch("include_hidden", true)
102
+ hidden_field + rendered_collection
103
+ else
104
+ rendered_collection
105
+ end
106
+ end
107
+
108
+ def hidden_field
109
+ hidden_name = @html_options[:name] || hidden_field_name
110
+ @template_object.hidden_field_tag(hidden_name, "", id: nil)
111
+ end
112
+
113
+ def hidden_field_name
114
+ "#{tag_name(false, @options[:index])}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end