Skip to content

Commit d10c3f6

Browse files
committed
use a better remove link for has_many_attachments
it's only for remove, there is no replacing, and adding doesn't require to click it
1 parent f8f0b95 commit d10c3f6

File tree

7 files changed

+92
-33
lines changed

7 files changed

+92
-33
lines changed

CHANGELOG.rdoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
- Add active_scaffold_subform_record_actions helper to render the destroy action on the rows of a subform, so it can be used to add more actions
1717
- Improve ActiveStorage bridge to keep existing files in has_many_attachments
1818
- Helpers used by file upload bridges have been renamed and moved the JS code to active_scaffold.js
19+
- Support action link groups to open with click, like actions showing dynamic action link group
20+
- Open dynamic action link group nested in the menu tree, under the action opening it
1921

20-
= 4-1-stable
22+
= 4.1.4
2123
- Fix dirty attributes on refresh_field action, record is built on unsaved instance copying attributes, but it reports only changed attributes from the form now
2224
- Fix incompatibility with Rails renderable objects (ViewComponent, Turbo Streams)
2325

app/assets/javascripts/jquery/active_scaffold.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
jQuery(document).on('focus', ':input', function() { ActiveScaffold.last_focus = this; });
4141
jQuery(document).on('blur', ':input', function(e) { ActiveScaffold.last_focus = e.relatedTarget; });
4242
jQuery(document).click(function(event) {
43-
jQuery('.action_group.dyn > ul').hide(); // only hide so action links loading still work
43+
if (!jQuery(event.target).closest('.action_group.dyn').length) {
44+
jQuery('.action_group.dyn > ul').remove();
45+
}
4446
});
4547
jQuery(document).on('ajax:beforeSend', 'form.as_form', function(event) {
4648
var as_form = jQuery(this).closest("form");
@@ -290,9 +292,13 @@
290292
} else return false;
291293
});
292294
jQuery(document).on('ajax:complete', '.action_group.dyn > ul a', function(event) {
293-
var action_link = ActiveScaffold.find_action_link(event.target);
294-
if (action_link && action_link.loading_indicator) action_link.loading_indicator.css('visibility','hidden');
295-
jQuery(event.target).closest('.action_group.dyn > ul').remove();
295+
var action_link = ActiveScaffold.find_action_link(event.target), link = jQuery(event.target);
296+
if (action_link && action_link.loading_indicator) action_link.loading_indicator.css('visibility', 'hidden');
297+
setTimeout(function() {
298+
if (!link.parent().is('.action_group.dyn')) {
299+
link.closest('.action_group.dyn > ul').remove();
300+
}
301+
}, 100);
296302
});
297303

298304
jQuery(document).on('change', 'input.update_form:not(.recordselect), textarea.update_form, select.update_form, .checkbox-list.update_form input:checkbox', function(event, additional_params) {
@@ -932,13 +938,12 @@
932938
display_dynamic_action_group: function(link, html) {
933939
var container;
934940
if (typeof(link) == 'string') link = jQuery('#' + link);
935-
if (link.closest('td.actions').length) {
936-
container = link.closest('td').addClass('action_group dyn');
937-
} else {
938-
if (link.parent('div.actions').length) link.wrap(jQuery('<div>'));
939-
container = link.parent().addClass('action_group dyn');
941+
if (link.parent('.actions').length) link.wrap(jQuery('<div>'));
942+
container = link.parent().addClass('action_group dyn');
943+
if (ActiveScaffold.config.dynamic_group_parent_class) {
944+
container.addClass(ActiveScaffold.config.dynamic_group_parent_class);
940945
}
941-
container.find('> ul').remove();
946+
container.find('> ul.dynamic-menu').remove();
942947
container.append(html);
943948
},
944949

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%= display_dynamic_action_group(@action_links, display_action_links(@action_links, @record, for: @record, output: []), @record) %>

lib/active_scaffold/actions/core.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,11 +548,11 @@ def association_columns(columns)
548548

549549
private
550550

551-
def respond_to_action(action)
551+
def respond_to_action(action, formats = action_formats)
552552
return unless !conditional_get_support? || view_stale?
553553

554554
respond_to do |type|
555-
action_formats.each do |format|
555+
formats.each do |format|
556556
type.send(format) do
557557
method_name = respond_method_for(action, format)
558558
send(method_name) if method_name

lib/active_scaffold/actions/list.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ def self.included(base)
88
end
99

1010
def index
11-
if params[:id] && !params[:id].is_a?(Array) && request.xhr?
11+
if params[:action_links] && request.xhr?
12+
action_links_menu
13+
elsif params[:id] && !params[:id].is_a?(Array) && request.xhr?
1214
row
1315
else
1416
list
@@ -17,6 +19,18 @@ def index
1719

1820
protected
1921

22+
def action_links_menu
23+
@record = find_if_allowed(params[:id], :read) if params[:id]
24+
@action_links = params[:action_links].split('.').reduce(active_scaffold_config.action_links) do |links, submenu|
25+
links.subgroup(submenu)
26+
end
27+
respond_to_action(:action_links_menu, action_links_menu_formats)
28+
end
29+
30+
def action_links_menu_formats
31+
%i[js]
32+
end
33+
2034
# get just a single row
2135
def row
2236
get_row
@@ -66,6 +80,10 @@ def row_respond_to_js
6680
render action: 'row'
6781
end
6882

83+
def action_links_menu_respond_to_js
84+
render action: 'action_links_menu'
85+
end
86+
6987
# The actual algorithm to prepare for the list view
7088
def set_includes_for_columns(action = :list, sorting = active_scaffold_config.list.user.sorting)
7189
@cache_associations = true

lib/active_scaffold/data_structures/action_links.rb

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,27 @@ module ActiveScaffold::DataStructures
44
class ActionLinks
55
include Enumerable
66

7+
COLLECTION_CLICK_MENU_LINK = ActionLink.new(:index, position: false, type: :member, parameters: {action_links: '--ACTION-LINKS--', id: nil}) # member so it's cached
8+
MEMBER_CLICK_MENU_LINK = ActionLink.new(:index, position: false, type: :member, parameters: {action_links: '--ACTION-LINKS--'})
9+
710
attr_accessor :default_type, :weight, :css_class
11+
attr_writer :click_menu, :label
12+
attr_reader :name, :path
813

9-
def initialize(name = :root)
14+
def initialize(name = :root, parent_path = nil)
1015
@set = []
1116
@name = name
1217
@css_class = name.to_s.downcase
1318
@weight = 0
19+
@path = [parent_path, name].compact.join('.') unless name == :root
20+
end
21+
22+
def click_menu?
23+
@click_menu
1424
end
1525

26+
alias name_to_cache path
27+
1628
# adds an ActionLink, creating one from the arguments if need be
1729
def add(action, options = {})
1830
link =
@@ -132,6 +144,7 @@ def collect
132144
delegate :empty?, to: :@set
133145

134146
def subgroup(name, label = nil)
147+
name = name.to_sym
135148
group = self if name == self.name
136149
group ||= @set.find do |item|
137150
name == item.name if item.is_a?(ActiveScaffold::DataStructures::ActionLinks)
@@ -140,16 +153,14 @@ def subgroup(name, label = nil)
140153
if group.nil?
141154
raise FrozenError, "Can't add new subgroup '#{name}', links are frozen" if frozen?
142155

143-
group = ActiveScaffold::DataStructures::ActionLinks.new(name)
156+
group = ActiveScaffold::DataStructures::ActionLinks.new(name, path)
144157
group.label = label || name
145-
group.default_type = self.name == :root ? (name.to_sym if %w[member collection].include?(name.to_s)) : default_type
158+
group.default_type = self.name == :root ? (name if %i[member collection].include?(name)) : default_type
146159
add_to_set group
147160
end
148161
group
149162
end
150163

151-
attr_writer :label
152-
153164
def label(record)
154165
case @label
155166
when Symbol
@@ -178,11 +189,9 @@ def method_missing(name, *args, &)
178189
end
179190

180191
def respond_to_missing?(name, *)
181-
name !~ /[!?]$/
192+
name !~ /[=!?]$/
182193
end
183194

184-
attr_reader :name
185-
186195
protected
187196

188197
# called during clone or dup. makes the clone/dup deeper.

lib/active_scaffold/helpers/action_link_helpers.rb

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def display_action_links(action_links, record, options, &block)
3535
options[:options_level_0_tag] ||= nil
3636
options[:level] ||= 0
3737
options[:first_action] = true
38-
output = ActiveSupport::SafeBuffer.new
38+
output = options[:output] || ActiveSupport::SafeBuffer.new
3939
prev_link = separator = nil
4040

4141
action_links.each(reverse: options.delete(:reverse), groups: true) do |link|
@@ -64,17 +64,37 @@ def display_action_links(action_links, record, options, &block)
6464
end
6565

6666
def display_action_link_group(link, record, options, &)
67-
options[:level] += 1
68-
content = display_action_links(link, record, options, &)
69-
options[:level] -= 1
70-
display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
67+
if link.click_menu?
68+
display_click_menu_link(link, record, options)
69+
else
70+
options[:level] += 1
71+
content = display_action_links(link, record, options, &)
72+
options[:level] -= 1
73+
display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
74+
end
7175
end
7276

7377
def display_action_link_separator(options)
7478
tag = options[:level_0_tag] || :a if options[:level].zero?
7579
content_tag(tag || :li, '&nbsp;'.html_safe, class: 'separator')
7680
end
7781

82+
def display_click_menu_link(link, record, options)
83+
action_link =
84+
if link.path.start_with?('collection.')
85+
ActiveScaffold::DataStructures::ActionLinks::COLLECTION_CLICK_MENU_LINK
86+
else
87+
ActiveScaffold::DataStructures::ActionLinks::MEMBER_CLICK_MENU_LINK
88+
end
89+
html = display_action_link(
90+
action_link,
91+
nil,
92+
record,
93+
options.merge(authorized: true, link: link.label(record), link_id: get_action_link_id(link, record))
94+
)
95+
html.gsub('--ACTION-LINKS--', ERB::Util.unwrapped_html_escape(link.path)).html_safe # rubocop:disable Rails/OutputSafety
96+
end
97+
7898
def display_action_link(link, content, record, options)
7999
if content
80100
html_classes = hover_via_click? ? 'hover_click ' : ''
@@ -129,7 +149,7 @@ def replace_tags_for_action_link(html, method, link, label, record, options) # r
129149
html = html.gsub('--REASON--', ERB::Util.unwrapped_html_escape(options[:not_authorized_reason]))
130150
when :render_authorized_action_link
131151
html = html.gsub('--URL--', ERB::Util.unwrapped_html_escape(action_link_url(link, record)))
132-
.gsub('--LINK_ID--', ERB::Util.unwrapped_html_escape(get_action_link_id(link, record)))
152+
.gsub('--LINK_ID--', ERB::Util.unwrapped_html_escape(options[:link_id] || get_action_link_id(link, record)))
133153
.gsub('--CONFIRM--') { ERB::Util.unwrapped_html_escape(link.confirm(h(record&.to_label))) }
134154
.gsub('--PROMPT--') { ERB::Util.unwrapped_html_escape(link.prompt(h(record&.to_label))) }
135155
.gsub('--ACTIVE--') { action_link_selected?(link, record) ? 'active' : '' }
@@ -400,7 +420,7 @@ def action_link_selected?(link, record)
400420
end
401421

402422
def action_link_html_options(link, record, options, cache: false)
403-
link_id = cache ? '--LINK_ID--' : get_action_link_id(link, record)
423+
link_id = cache ? '--LINK_ID--' : options[:link_id] || get_action_link_id(link, record)
404424
html_options = options[:html_options] || link.html_options
405425
html_options = html_options.merge(class: [html_options[:class], link.action.to_s].compact.join(' '))
406426
html_options[:link] = action_link_text(link, record, options)
@@ -442,7 +462,7 @@ def action_link_html_options(link, record, options, cache: false)
442462
end
443463

444464
def get_action_link_id(link, record = nil)
445-
column = link.column
465+
column = link.column unless link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
446466
if column&.association && record
447467
associated = record.send(column.association.name) unless column.association.collection?
448468
id =
@@ -454,10 +474,14 @@ def get_action_link_id(link, record = nil)
454474
end
455475
id ||= record&.id&.to_s || (nested? ? nested_parent_id.to_s : '')
456476
action_link_id = ActiveScaffold::Registry.cache :action_link_id, link.name_to_cache.to_s do
457-
if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
458-
controller_id = id_from_controller("#{link.controller}-")
477+
if link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
478+
action_link_id(link.path.tr('.', '_'), '--ID--')
479+
else
480+
if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
481+
controller_id = id_from_controller("#{link.controller}-")
482+
end
483+
action_link_id("#{controller_id}#{link.action}", '--ID--')
459484
end
460-
action_link_id("#{controller_id}#{link.action}", '--ID--')
461485
end
462486
action_link_id.sub('--ID--', id)
463487
end

0 commit comments

Comments
 (0)