active_scaffold 4.1.6 → 4.2.1

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.
Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +32 -0
  3. data/README.md +8 -6
  4. data/app/assets/javascripts/jquery/active_scaffold.js +103 -51
  5. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +35 -2
  6. data/app/assets/stylesheets/active_scaffold_images.scss +6 -0
  7. data/app/assets/stylesheets/{active_scaffold_layout.css → active_scaffold_layout.scss} +104 -4
  8. data/app/assets/stylesheets/tiny_mce_bridge.scss +11 -0
  9. data/app/views/active_scaffold_overrides/_base_form.html.erb +3 -2
  10. data/app/views/active_scaffold_overrides/_field_search.html.erb +2 -2
  11. data/app/views/active_scaffold_overrides/_form.html.erb +14 -4
  12. data/app/views/active_scaffold_overrides/_form_association.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +5 -11
  14. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  15. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -3
  16. data/app/views/active_scaffold_overrides/_new_record.js.erb +3 -1
  17. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +1 -1
  18. data/app/views/active_scaffold_overrides/_render_field.js.erb +67 -36
  19. data/app/views/active_scaffold_overrides/_update_field_on_create.js.erb +41 -6
  20. data/app/views/active_scaffold_overrides/action_links_menu.js.erb +1 -0
  21. data/config/locales/de.yml +9 -0
  22. data/config/locales/en.yml +11 -0
  23. data/config/locales/es.yml +8 -0
  24. data/config/locales/fr.yml +8 -0
  25. data/config/locales/hu.yml +8 -0
  26. data/config/locales/ja.yml +8 -0
  27. data/config/locales/ru.yml +8 -0
  28. data/lib/active_scaffold/actions/common_search.rb +2 -0
  29. data/lib/active_scaffold/actions/core.rb +47 -23
  30. data/lib/active_scaffold/actions/create.rb +2 -0
  31. data/lib/active_scaffold/actions/delete.rb +6 -0
  32. data/lib/active_scaffold/actions/field_search.rb +36 -11
  33. data/lib/active_scaffold/actions/list.rb +26 -8
  34. data/lib/active_scaffold/actions/mark.rb +6 -0
  35. data/lib/active_scaffold/actions/nested.rb +2 -0
  36. data/lib/active_scaffold/actions/search.rb +7 -0
  37. data/lib/active_scaffold/actions/show.rb +6 -0
  38. data/lib/active_scaffold/actions/subform.rb +2 -0
  39. data/lib/active_scaffold/actions/update.rb +8 -1
  40. data/lib/active_scaffold/active_record_permissions.rb +3 -3
  41. data/lib/active_scaffold/attribute_params.rb +35 -17
  42. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +2 -0
  43. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +10 -9
  44. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +10 -3
  45. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +2 -0
  46. data/lib/active_scaffold/bridges/active_storage.rb +2 -0
  47. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +2 -0
  48. data/lib/active_scaffold/bridges/ancestry.rb +2 -0
  49. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +2 -0
  50. data/lib/active_scaffold/bridges/bitfields/list_ui.rb +2 -0
  51. data/lib/active_scaffold/bridges/bitfields.rb +2 -0
  52. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -6
  53. data/lib/active_scaffold/bridges/cancan.rb +2 -0
  54. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +2 -0
  55. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +2 -0
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +3 -1
  57. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -0
  58. data/lib/active_scaffold/bridges/carrierwave.rb +2 -0
  59. data/lib/active_scaffold/bridges/chosen/helpers.rb +13 -4
  60. data/lib/active_scaffold/bridges/chosen.rb +2 -0
  61. data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +2 -0
  62. data/lib/active_scaffold/bridges/country_select.rb +2 -0
  63. data/lib/active_scaffold/bridges/date_picker/ext.rb +6 -0
  64. data/lib/active_scaffold/bridges/date_picker/helper.rb +7 -3
  65. data/lib/active_scaffold/bridges/date_picker.rb +2 -0
  66. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +2 -0
  67. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +2 -0
  68. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -1
  69. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +2 -0
  70. data/lib/active_scaffold/bridges/dragonfly.rb +2 -0
  71. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +2 -0
  72. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +10 -9
  73. data/lib/active_scaffold/bridges/file_column/form_ui.rb +2 -0
  74. data/lib/active_scaffold/bridges/file_column/list_ui.rb +2 -0
  75. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +2 -0
  76. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +2 -0
  77. data/lib/active_scaffold/bridges/file_column.rb +2 -0
  78. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.rb +65 -0
  79. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.treetop +31 -0
  80. data/lib/active_scaffold/bridges/logical_query_parser.rb +9 -0
  81. data/lib/active_scaffold/bridges/paper_trail/actions.rb +2 -0
  82. data/lib/active_scaffold/bridges/paper_trail/config.rb +2 -0
  83. data/lib/active_scaffold/bridges/paper_trail/helper.rb +2 -0
  84. data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +2 -0
  85. data/lib/active_scaffold/bridges/paper_trail.rb +2 -0
  86. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -1
  87. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +2 -0
  88. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +2 -0
  89. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +12 -12
  90. data/lib/active_scaffold/bridges/paperclip.rb +2 -0
  91. data/lib/active_scaffold/bridges/record_select/helpers.rb +19 -11
  92. data/lib/active_scaffold/bridges/record_select.rb +2 -0
  93. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +2 -0
  94. data/lib/active_scaffold/bridges/semantic_attributes.rb +2 -0
  95. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  96. data/lib/active_scaffold/bridges/tiny_mce.rb +6 -0
  97. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +2 -0
  98. data/lib/active_scaffold/bridges/usa_state_select.rb +2 -0
  99. data/lib/active_scaffold/bridges.rb +2 -0
  100. data/lib/active_scaffold/config/base.rb +12 -7
  101. data/lib/active_scaffold/config/core.rb +26 -23
  102. data/lib/active_scaffold/config/create.rb +2 -0
  103. data/lib/active_scaffold/config/delete.rb +2 -0
  104. data/lib/active_scaffold/config/field_search.rb +2 -0
  105. data/lib/active_scaffold/config/form.rb +11 -1
  106. data/lib/active_scaffold/config/list.rb +7 -7
  107. data/lib/active_scaffold/config/mark.rb +2 -0
  108. data/lib/active_scaffold/config/nested.rb +28 -0
  109. data/lib/active_scaffold/config/search.rb +2 -0
  110. data/lib/active_scaffold/config/show.rb +2 -0
  111. data/lib/active_scaffold/config/subform.rb +2 -0
  112. data/lib/active_scaffold/config/update.rb +3 -1
  113. data/lib/active_scaffold/configurable.rb +4 -2
  114. data/lib/active_scaffold/constraints.rb +2 -0
  115. data/lib/active_scaffold/core.rb +14 -4
  116. data/lib/active_scaffold/data_structures/action_columns.rb +3 -1
  117. data/lib/active_scaffold/data_structures/action_link.rb +10 -0
  118. data/lib/active_scaffold/data_structures/action_link_separator.rb +2 -0
  119. data/lib/active_scaffold/data_structures/action_links.rb +32 -21
  120. data/lib/active_scaffold/data_structures/actions.rb +4 -2
  121. data/lib/active_scaffold/data_structures/association/abstract.rb +4 -2
  122. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +4 -2
  123. data/lib/active_scaffold/data_structures/association/active_record.rb +3 -9
  124. data/lib/active_scaffold/data_structures/association/mongoid.rb +4 -2
  125. data/lib/active_scaffold/data_structures/association.rb +2 -0
  126. data/lib/active_scaffold/data_structures/bridge.rb +3 -1
  127. data/lib/active_scaffold/data_structures/column.rb +37 -3
  128. data/lib/active_scaffold/data_structures/columns.rb +4 -2
  129. data/lib/active_scaffold/data_structures/filter.rb +3 -3
  130. data/lib/active_scaffold/data_structures/filter_option.rb +2 -0
  131. data/lib/active_scaffold/data_structures/filters.rb +3 -3
  132. data/lib/active_scaffold/data_structures/nested_info.rb +4 -2
  133. data/lib/active_scaffold/data_structures/set.rb +8 -10
  134. data/lib/active_scaffold/data_structures/sorting.rb +5 -7
  135. data/lib/active_scaffold/engine.rb +3 -4
  136. data/lib/active_scaffold/extensions/action_controller_rendering.rb +2 -0
  137. data/lib/active_scaffold/extensions/action_controller_rescueing.rb +2 -0
  138. data/lib/active_scaffold/extensions/action_view_rendering.rb +2 -0
  139. data/lib/active_scaffold/extensions/connection_adapter.rb +2 -0
  140. data/lib/active_scaffold/extensions/ice_nine.rb +2 -0
  141. data/lib/active_scaffold/extensions/localize.rb +2 -0
  142. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +2 -0
  143. data/lib/active_scaffold/extensions/paginator_extensions.rb +3 -1
  144. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -0
  145. data/lib/active_scaffold/extensions/to_label.rb +2 -0
  146. data/lib/active_scaffold/extensions/unsaved_associated.rb +10 -8
  147. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -0
  148. data/lib/active_scaffold/finder.rb +57 -18
  149. data/lib/active_scaffold/helpers/action_link_helpers.rb +112 -37
  150. data/lib/active_scaffold/helpers/association_helpers.rb +4 -2
  151. data/lib/active_scaffold/helpers/controller_helpers.rb +2 -0
  152. data/lib/active_scaffold/helpers/filter_helpers.rb +11 -3
  153. data/lib/active_scaffold/helpers/form_column_helpers.rb +145 -110
  154. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -0
  155. data/lib/active_scaffold/helpers/id_helpers.rb +2 -0
  156. data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -5
  157. data/lib/active_scaffold/helpers/pagination_helpers.rb +3 -1
  158. data/lib/active_scaffold/helpers/search_column_helpers.rb +19 -9
  159. data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -2
  160. data/lib/active_scaffold/helpers/tabs_helpers.rb +5 -3
  161. data/lib/active_scaffold/helpers/view_helpers.rb +3 -3
  162. data/lib/active_scaffold/marked_model.rb +6 -5
  163. data/lib/active_scaffold/orm_checks.rb +2 -0
  164. data/lib/active_scaffold/paginator.rb +4 -1
  165. data/lib/active_scaffold/registry.rb +2 -0
  166. data/lib/active_scaffold/responds_to_parent.rb +2 -0
  167. data/lib/active_scaffold/tableless.rb +23 -13
  168. data/lib/active_scaffold/version.rb +4 -2
  169. data/lib/active_scaffold.rb +10 -2
  170. data/lib/generators/active_scaffold/controller/USAGE +19 -0
  171. data/lib/generators/active_scaffold/controller/controller_generator.rb +29 -0
  172. data/lib/generators/active_scaffold/install/USAGE +2 -0
  173. data/lib/generators/active_scaffold/{install_generator.rb → install/install_generator.rb} +10 -6
  174. data/lib/generators/active_scaffold/resource/USAGE +29 -0
  175. data/lib/generators/active_scaffold/resource/resource_generator.rb +30 -0
  176. data/lib/tasks/brakeman.rake +2 -0
  177. data/shoulda_macros/macros.rb +2 -0
  178. metadata +19 -11
  179. data/lib/generators/active_scaffold/controller_generator.rb +0 -49
  180. data/lib/generators/active_scaffold/resource_generator.rb +0 -56
  181. /data/lib/generators/{templates → active_scaffold/controller/templates}/controller.rb +0 -0
  182. /data/lib/generators/{templates → active_scaffold/controller/templates}/helper.rb +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  # Helpers rendering action links
@@ -5,16 +7,16 @@ module ActiveScaffold
5
7
  # params which mustn't be copying to nested links
6
8
  NESTED_PARAMS = %i[eid embedded association parent_scaffold].freeze
7
9
 
8
- def skip_action_link?(link, *args)
9
- !link.ignore_method.nil? && controller.respond_to?(link.ignore_method, true) && controller.send(link.ignore_method, *args)
10
+ def skip_action_link?(link, *)
11
+ !link.ignore_method.nil? && controller.respond_to?(link.ignore_method, true) && controller.send(link.ignore_method, *)
10
12
  end
11
13
 
12
- def action_link_authorized?(link, *args)
14
+ def action_link_authorized?(link, *args) # rubocop:disable Naming/PredicateMethod
13
15
  auth, reason =
14
16
  if link.security_method_set? || controller.respond_to?(link.security_method, true)
15
17
  controller.send(link.security_method, *args)
16
18
  else
17
- args.empty? ? true : args.first.authorized_for?(crud_type: link.crud_type, action: link.action, reason: true)
19
+ args.empty? || args.first.authorized_for?(crud_type: link.crud_type, action: link.action, reason: true)
18
20
  end
19
21
  [auth, reason]
20
22
  end
@@ -22,6 +24,8 @@ module ActiveScaffold
22
24
  def display_dynamic_action_group(action_link, links, record_or_ul_options = nil, ul_options = nil)
23
25
  ul_options = record_or_ul_options if ul_options.nil? && record_or_ul_options.is_a?(Hash)
24
26
  record = record_or_ul_options unless record_or_ul_options.is_a?(Hash)
27
+ ul_options ||= {}
28
+ ul_options[:class] = [ul_options[:class], 'dynamic-menu'].compact.join(' ')
25
29
  html = content_tag :ul, ul_options do
26
30
  safe_join(links.map { |link| content_tag :li, link })
27
31
  end
@@ -33,7 +37,7 @@ module ActiveScaffold
33
37
  options[:options_level_0_tag] ||= nil
34
38
  options[:level] ||= 0
35
39
  options[:first_action] = true
36
- output = ActiveSupport::SafeBuffer.new
40
+ output = options.delete(:output) || ActiveSupport::SafeBuffer.new
37
41
  prev_link = separator = nil
38
42
 
39
43
  action_links.each(reverse: options.delete(:reverse), groups: true) do |link|
@@ -62,10 +66,14 @@ module ActiveScaffold
62
66
  end
63
67
 
64
68
  def display_action_link_group(link, record, options, &)
65
- options[:level] += 1
66
- content = display_action_links(link, record, options, &)
67
- options[:level] -= 1
68
- display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
69
+ if link.click_menu?
70
+ display_click_menu_link(link, record, options)
71
+ else
72
+ options[:level] += 1
73
+ content = display_action_links(link, record, options, &)
74
+ options[:level] -= 1
75
+ display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
76
+ end
69
77
  end
70
78
 
71
79
  def display_action_link_separator(options)
@@ -73,14 +81,30 @@ module ActiveScaffold
73
81
  content_tag(tag || :li, ' '.html_safe, class: 'separator')
74
82
  end
75
83
 
84
+ def display_click_menu_link(link, record, options)
85
+ action_link =
86
+ if link.path.start_with?('collection.')
87
+ ActiveScaffold::DataStructures::ActionLinks::COLLECTION_CLICK_MENU_LINK
88
+ else
89
+ ActiveScaffold::DataStructures::ActionLinks::MEMBER_CLICK_MENU_LINK
90
+ end
91
+ html = display_action_link(
92
+ action_link,
93
+ nil,
94
+ record,
95
+ options.merge(authorized: true, link: link.label(record), link_id: get_action_link_id(link, record))
96
+ )
97
+ html.gsub('--ACTION-LINKS--', ERB::Util.unwrapped_html_escape(link.path)).html_safe # rubocop:disable Rails/OutputSafety
98
+ end
99
+
76
100
  def display_action_link(link, content, record, options)
77
101
  if content
78
102
  html_classes = hover_via_click? ? 'hover_click ' : ''
79
103
  if options[:level].zero?
80
- html_classes << 'action_group'
104
+ html_classes += 'action_group'
81
105
  group_tag = :div
82
106
  else
83
- html_classes << 'top' if options[:first_action]
107
+ html_classes += 'top' if options[:first_action]
84
108
  group_tag = :li
85
109
  end
86
110
  content = content_tag(group_tag, class: html_classes.presence, onclick: ('' if hover_via_click?)) do
@@ -100,17 +124,61 @@ module ActiveScaffold
100
124
  options[:authorized] = false if link.action.nil? || link.controller.nil?
101
125
  options.delete :link if link.crud_type == :create
102
126
  end
103
- if link.action.nil? || (link.type == :member && options.key?(:authorized) && !options[:authorized])
104
- html_class = "disabled #{link.action}#{" #{link.html_options[:class]}" if link.html_options[:class].present?}"
105
- html_options = {link: action_link_text(link, record, options), class: html_class, title: options[:not_authorized_reason]}
106
- action_link_html(link, nil, html_options, record)
127
+ method =
128
+ if link.action.nil? || (link.type == :member && options.key?(:authorized) && !options[:authorized])
129
+ :render_unauthorized_action_link
130
+ else
131
+ :render_authorized_action_link
132
+ end
133
+
134
+ cache_link = cache_action_link?(link)
135
+ label = options[:link]
136
+ result = optional_cache_helper(method, link.name_to_cache.to_s, cache_link, link, record, options, cache: cache_link)
137
+ cache_link ? replace_tags_for_action_link(result, method, link, label, record, options) : result
138
+ end
139
+
140
+ def optional_cache_helper(method, key, cache, ...)
141
+ if cache
142
+ ActiveScaffold::Registry.cache(method, key) { send(method, ...) }
107
143
  else
108
- url = action_link_url(link, record)
109
- html_options = action_link_html_options(link, record, options)
110
- action_link_html(link, url, html_options, record)
144
+ send(method, ...)
111
145
  end
112
146
  end
113
147
 
148
+ def replace_tags_for_action_link(html, method, link, label, record, options) # rubocop:disable Metrics/ParameterLists
149
+ case method
150
+ when :render_unauthorized_action_link
151
+ html = html.gsub('--REASON--', ERB::Util.unwrapped_html_escape(options[:not_authorized_reason]))
152
+ when :render_authorized_action_link
153
+ html = html.gsub('--URL--', ERB::Util.unwrapped_html_escape(action_link_url(link, record)))
154
+ .gsub('--LINK_ID--', ERB::Util.unwrapped_html_escape(options[:link_id] || get_action_link_id(link, record)))
155
+ .gsub('--CONFIRM--') { ERB::Util.unwrapped_html_escape(link.confirm(h(record&.to_label))) }
156
+ .gsub('--PROMPT--') { ERB::Util.unwrapped_html_escape(link.prompt(h(record&.to_label))) }
157
+ .gsub('--ACTIVE--') { action_link_selected?(link, record) ? 'active' : '' }
158
+ end
159
+ html&.gsub('--LABEL--', h(label || link.label(record)))&.html_safe # rubocop:disable Rails/OutputSafety
160
+ end
161
+
162
+ def render_unauthorized_action_link(link, record = nil, options = {}, cache: false)
163
+ html_class = "disabled #{link.action}#{" #{link.html_options[:class]}" if link.html_options[:class].present?}"
164
+ options[:link] = '--LABEL--' if cache
165
+ html_options = {
166
+ link: action_link_text(link, record, options),
167
+ class: html_class,
168
+ title: cache ? '--REASON--' : options[:not_authorized_reason]
169
+ }
170
+ html = action_link_html(link, nil, html_options, record)
171
+ cache ? html.to_str : html
172
+ end
173
+
174
+ def render_authorized_action_link(link, record = nil, options = {}, cache: false)
175
+ url = cache ? '--URL--' : action_link_url(link, record)
176
+ options[:link] = '--LABEL--' if cache
177
+ html_options = action_link_html_options(link, record, options, cache: cache)
178
+ html = action_link_html(link, url, html_options, record)
179
+ cache ? html.to_str : html
180
+ end
181
+
114
182
  # setup the action link to inline form
115
183
  def action_link_to_inline_form(link, record)
116
184
  link = link.dup
@@ -182,6 +250,10 @@ module ActiveScaffold
182
250
  active_scaffold_config.user.cache_action_link_urls && link.type == :member && !link.dynamic_parameters.is_a?(Proc) && !sti_record?(record)
183
251
  end
184
252
 
253
+ def cache_action_link?(link)
254
+ active_scaffold_config.user.cache_action_links && link.type == :member
255
+ end
256
+
185
257
  def cached_action_link_url(link, record)
186
258
  @action_links_urls ||= {}
187
259
  @action_links_urls[link.name_to_cache.to_s] || begin
@@ -196,7 +268,7 @@ module ActiveScaffold
196
268
  end
197
269
 
198
270
  def replace_id_params_in_action_link_url(link, record, url)
199
- url = record ? url.sub('--ID--', record.to_param.to_s) : url.clone
271
+ url = record ? url.sub('--ID--', record.to_param.to_s) : url.dup
200
272
  if link.column&.association&.singular?
201
273
  child_id = record.send(link.column.association.name)&.to_param
202
274
  if child_id.present?
@@ -284,12 +356,7 @@ module ActiveScaffold
284
356
  end
285
357
 
286
358
  def cached_action_link_url_options(link, record)
287
- @action_links_url_options ||= {}
288
- @action_links_url_options[link.name_to_cache.to_s] || begin
289
- options = action_link_url_options(link, record)
290
- @action_links_url_options[link.name_to_cache.to_s] = options if cache_action_link_url_options?(link, record)
291
- options
292
- end
359
+ optional_cache_helper(:action_link_url_options, link.name_to_cache.to_s, cache_action_link_url_options?(link, record), link, record)
293
360
  end
294
361
 
295
362
  def action_link_url_options(link, record)
@@ -317,7 +384,7 @@ module ActiveScaffold
317
384
  def action_link_text(link, record, options)
318
385
  if link.image
319
386
  title = options[:link] || link.label(record)
320
- asset = (@_link_images ||= {})[link.image[:name]] ||= image_path(link.image[:name])
387
+ asset = ActiveScaffold::Registry.cache(:link_images, link.image[:name]) { image_path(link.image[:name]) }
321
388
  text = image_tag(asset, size: link.image[:size], alt: title, title: title, skip_pipeline: true)
322
389
  end
323
390
  text || options[:link]
@@ -354,8 +421,8 @@ module ActiveScaffold
354
421
  end
355
422
  end
356
423
 
357
- def action_link_html_options(link, record, options)
358
- link_id = get_action_link_id(link, record)
424
+ def action_link_html_options(link, record, options, cache: false)
425
+ link_id = cache ? '--LINK_ID--' : options[:link_id] || get_action_link_id(link, record)
359
426
  html_options = options[:html_options] || link.html_options
360
427
  html_options = html_options.merge(class: [html_options[:class], link.action.to_s].compact.join(' '))
361
428
  html_options[:link] = action_link_text(link, record, options)
@@ -365,23 +432,27 @@ module ActiveScaffold
365
432
 
366
433
  html_options[:data] ||= {}
367
434
  html_options[:data] = html_options[:data].deep_dup if html_options[:data].frozen?
368
- html_options[:data][:confirm] = link.confirm(h(record&.to_label)) if link.confirm?
435
+ html_options[:data][:confirm] = cache ? '--CONFIRM--' : link.confirm(h(record&.to_label)) if link.confirm?
369
436
  if !options[:page] && !options[:popup] && (options[:inline] || link.inline?)
370
- html_options[:class] << ' as_action'
437
+ html_options[:class] += ' as_action'
371
438
  html_options[:data][:position] = link.position if link.position
372
439
  html_options[:data][:action] = link.action
373
440
  html_options[:data][:cancel_refresh] = true if link.refresh_on_close
374
441
  html_options[:data][:keep_open] = true if link.keep_open?
375
442
  if link.prompt?
376
- html_options[:data][:prompt] = link.prompt(h(record&.to_label))
443
+ html_options[:data][:prompt] = cache ? '--PROMPT--' : link.prompt(h(record&.to_label))
377
444
  html_options[:data][:prompt_required] = true if link.prompt_required?
378
445
  end
379
446
  html_options[:remote] = true
380
447
  end
381
448
 
382
449
  if link.toggle
383
- html_options[:class] << ' toggle'
384
- html_options[:class] << ' active' if action_link_selected?(link, record)
450
+ html_options[:class] += ' toggle'
451
+ if cache
452
+ html_options[:class] << ' --ACTIVE--'
453
+ elsif action_link_selected?(link, record)
454
+ html_options[:class] << ' active'
455
+ end
385
456
  end
386
457
 
387
458
  if !options[:page] && !options[:inline] && (options[:popup] || link.popup?)
@@ -393,7 +464,7 @@ module ActiveScaffold
393
464
  end
394
465
 
395
466
  def get_action_link_id(link, record = nil)
396
- column = link.column
467
+ column = link.column unless link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
397
468
  if column&.association && record
398
469
  associated = record.send(column.association.name) unless column.association.collection?
399
470
  id =
@@ -405,10 +476,14 @@ module ActiveScaffold
405
476
  end
406
477
  id ||= record&.id&.to_s || (nested? ? nested_parent_id.to_s : '')
407
478
  action_link_id = ActiveScaffold::Registry.cache :action_link_id, link.name_to_cache.to_s do
408
- if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
409
- controller_id = id_from_controller("#{link.controller}-")
479
+ if link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
480
+ action_link_id(link.path.tr('.', '_'), '--ID--')
481
+ else
482
+ if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
483
+ controller_id = id_from_controller("#{link.controller}-")
484
+ end
485
+ action_link_id("#{controller_id}#{link.action}", '--ID--')
410
486
  end
411
- action_link_id("#{controller_id}#{link.action}", '--ID--')
412
487
  end
413
488
  action_link_id.sub('--ID--', id)
414
489
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  module AssociationHelpers
@@ -39,7 +41,7 @@ module ActiveScaffold
39
41
  include_assoc = includes_for_association(column, klass)
40
42
  relation = relation.includes(include_assoc) if include_assoc
41
43
  end
42
- if column&.sort && column.sort&.dig(:sql)
44
+ if column&.sort&.dig(:sql)
43
45
  # with threasafe enabled, column.sort[:sql] returns proxied strings and
44
46
  # regexp capture won't work, which rails uses internally, so to_s is needed
45
47
  relation = relation.order(Array(column.sort[:sql]).map { |sql| Arel.sql(sql.to_s) })
@@ -92,7 +94,7 @@ module ActiveScaffold
92
94
  def sorted_association_options_find(association, conditions = nil, record = nil)
93
95
  options = association_options_find(association, conditions, nil, record)
94
96
  column = column_for_association(association, record)
95
- unless column&.sort && column.sort&.dig(:sql)
97
+ unless column&.sort&.dig(:sql)
96
98
  method = column.options[:label_method] if column
97
99
  options = options.sort_by(&(method || :to_label).to_sym)
98
100
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  module ControllerHelpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  # Helpers rendering filters
@@ -9,8 +11,14 @@ module ActiveScaffold
9
11
  end
10
12
 
11
13
  def display_filters(filters)
12
- content = filters.sort_by(&:weight).map { |filter| display_filter(filter) }
13
- content_tag :div, safe_join(content), class: 'filters' if content.present?
14
+ return unless filters_enabled?
15
+
16
+ content = render_filters filters
17
+ content_tag :div, content, class: 'filters' if content.present?
18
+ end
19
+
20
+ def render_filters(filters)
21
+ safe_join(filters.sort_by(&:weight).filter_map { |filter| display_filter(filter) })
14
22
  end
15
23
 
16
24
  def display_filter(filter)
@@ -29,7 +37,7 @@ module ActiveScaffold
29
37
  content = options.map do |option|
30
38
  content_tag :option, option.label(nil), data: {url: action_link_url(option, nil)}, selected: action_link_selected?(option, nil), title: option.description
31
39
  end
32
- select_tag nil, safe_join(content), class: "action_group #{link.css_class}", title: filter.description || filter.label, data: {remote: :url} if content.present?
40
+ select_tag nil, safe_join(content), class: "action_group #{filter.css_class}", title: filter.description || filter.label, data: {remote: :url} if content.present?
33
41
  end
34
42
  end
35
43
  end