super 0.19.0 → 0.20.0
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.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/app/controllers/super/application_controller.rb +2 -2
- data/app/controllers/super/substructure_controller.rb +24 -1
- data/app/helpers/super/form_builder_helper.rb +4 -4
- data/app/views/super/application/_batch_checkbox.html.erb +4 -0
- data/app/views/super/application/_form.html.erb +1 -1
- data/app/views/super/application/_pagination.html.erb +1 -4
- data/app/views/super/application/_site_footer.html.erb +1 -1
- data/config/locales/en.yml +7 -1
- data/frontend/super-frontend/dist/application.js +6276 -6286
- data/frontend/super-frontend/dist/package.json +2 -2
- data/lib/super/action_inquirer.rb +3 -0
- data/lib/super/error.rb +1 -0
- data/lib/super/form/schema_types.rb +8 -36
- data/lib/super/form_builder/action_text_methods.rb +16 -0
- data/lib/super/form_builder/base_methods.rb +73 -0
- data/lib/super/form_builder/flatpickr_methods.rb +75 -0
- data/lib/super/form_builder/option_methods.rb +73 -0
- data/lib/super/form_builder.rb +143 -0
- data/lib/super/link.rb +47 -63
- data/lib/super/link_builder.rb +24 -43
- data/lib/super/useful/i19.rb +35 -0
- data/lib/super/version.rb +1 -1
- data/lib/super.rb +6 -1
- metadata +13 -8
- data/lib/super/form/builder.rb +0 -289
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@superadministration/super",
|
3
3
|
"description": "The frontend code for Super, a Rails admin framework",
|
4
|
-
"homepage": "https://github.com/
|
4
|
+
"homepage": "https://github.com/superadministration/super",
|
5
5
|
"license": "LGPL-3.0-only",
|
6
6
|
"main": "application.js",
|
7
7
|
"files": [
|
@@ -9,5 +9,5 @@
|
|
9
9
|
"application.css",
|
10
10
|
"package.json"
|
11
11
|
],
|
12
|
-
"version": "0.
|
12
|
+
"version": "0.20.0"
|
13
13
|
}
|
data/lib/super/error.rb
CHANGED
@@ -105,42 +105,6 @@ module Super
|
|
105
105
|
Direct.new(super_builder: super_builder, method_name: method_name, args: args, kwargs: kwargs)
|
106
106
|
end
|
107
107
|
|
108
|
-
def select(*args, **kwargs)
|
109
|
-
Direct.new(super_builder: true, method_name: :select!, args: args, kwargs: kwargs)
|
110
|
-
end
|
111
|
-
|
112
|
-
def text_field(*args, **kwargs)
|
113
|
-
Direct.new(super_builder: true, method_name: :text_field!, args: args, kwargs: kwargs)
|
114
|
-
end
|
115
|
-
|
116
|
-
def rich_text_area(*args, **kwargs)
|
117
|
-
Direct.new(super_builder: true, method_name: :rich_text_area!, args: args, kwargs: kwargs)
|
118
|
-
end
|
119
|
-
|
120
|
-
def check_box(*args, **kwargs)
|
121
|
-
Direct.new(super_builder: true, method_name: :check_box!, args: args, kwargs: kwargs)
|
122
|
-
end
|
123
|
-
|
124
|
-
def date_flatpickr(*args, **kwargs)
|
125
|
-
Direct.new(super_builder: true, method_name: :date_flatpickr!, args: args, kwargs: kwargs)
|
126
|
-
end
|
127
|
-
|
128
|
-
def datetime_flatpickr(*args, **kwargs)
|
129
|
-
Direct.new(super_builder: true, method_name: :datetime_flatpickr!, args: args, kwargs: kwargs)
|
130
|
-
end
|
131
|
-
|
132
|
-
def hidden_field(*args, **kwargs)
|
133
|
-
Direct.new(super_builder: false, method_name: :hidden_field, args: args, kwargs: kwargs)
|
134
|
-
end
|
135
|
-
|
136
|
-
def password_field(*args, **kwargs)
|
137
|
-
Direct.new(super_builder: true, method_name: :password_field!, args: args, kwargs: kwargs)
|
138
|
-
end
|
139
|
-
|
140
|
-
def time_flatpickr(*args, **kwargs)
|
141
|
-
Direct.new(super_builder: true, method_name: :time_flatpickr!, args: args, kwargs: kwargs)
|
142
|
-
end
|
143
|
-
|
144
108
|
def has_many(reader, **extras)
|
145
109
|
subfields = Schema::Fields.new
|
146
110
|
@fields.nested do
|
@@ -176,6 +140,14 @@ module Super
|
|
176
140
|
nested: {}
|
177
141
|
)
|
178
142
|
end
|
143
|
+
|
144
|
+
def self.define_schema_type_for(method_name)
|
145
|
+
class_eval(<<~RUBY)
|
146
|
+
def #{method_name}(*args, **kwargs)
|
147
|
+
Direct.new(super_builder: true, method_name: :#{method_name}!, args: args, kwargs: kwargs)
|
148
|
+
end
|
149
|
+
RUBY
|
150
|
+
end
|
179
151
|
end
|
180
152
|
end
|
181
153
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Super
|
4
|
+
class FormBuilder
|
5
|
+
class Wrappers
|
6
|
+
def rich_text_area(attribute, options = {})
|
7
|
+
options, defaults = split_defaults(options, class: "trix-content super-input w-full")
|
8
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
9
|
+
|
10
|
+
@builder.rich_text_area(attribute, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
define_convenience :rich_text_area
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Super
|
4
|
+
class FormBuilder
|
5
|
+
class Wrappers
|
6
|
+
skipped_field_helpers = [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]
|
7
|
+
(ActionView::Helpers::FormBuilder.field_helpers - skipped_field_helpers).each do |builder_method_name|
|
8
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
9
|
+
def #{builder_method_name}(attribute, options = {})
|
10
|
+
options, defaults = split_defaults(options, class: "super-input w-full")
|
11
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
12
|
+
|
13
|
+
@builder.#{builder_method_name}(attribute, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
define_convenience :#{builder_method_name}
|
17
|
+
RUBY
|
18
|
+
end
|
19
|
+
|
20
|
+
def label(attribute, text = nil, options = {}, &block)
|
21
|
+
options, defaults = split_defaults(options, class: "block")
|
22
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
23
|
+
|
24
|
+
@builder.label(attribute, text, options, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0")
|
28
|
+
@builder.check_box(attribute, options, checked_value, unchecked_value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_box!(attribute, checked_value: "1", unchecked_value: "0", label_text: nil, label: {}, field: {}, show_errors: true)
|
32
|
+
label[:super] ||= {}
|
33
|
+
label[:super] = { class: "select-none ml-1" }.merge(label[:super])
|
34
|
+
container do
|
35
|
+
compact_join([
|
36
|
+
"<div>".html_safe,
|
37
|
+
public_send(:check_box, attribute, field, checked_value, unchecked_value),
|
38
|
+
public_send(:label, attribute, label_text, label),
|
39
|
+
"</div>".html_safe,
|
40
|
+
show_errors && inline_errors(attribute),
|
41
|
+
])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
::Super::Form::SchemaTypes.define_schema_type_for(:check_box)
|
46
|
+
|
47
|
+
# def file_field(attribute, options = {})
|
48
|
+
# end
|
49
|
+
|
50
|
+
# def file_field!(attribute, label_text: nil, label: {}, field: {}, show_errors: true)
|
51
|
+
# end
|
52
|
+
|
53
|
+
def hidden_field(attribute, options = {})
|
54
|
+
@builder.hidden_field(attribute, options)
|
55
|
+
end
|
56
|
+
|
57
|
+
# def radio_button(attribute, tag_value, options = {})
|
58
|
+
# @builder.radio_button(attribute, tag_value, options)
|
59
|
+
# end
|
60
|
+
|
61
|
+
# def radio_button(attribute, tag_value, label_text: nil, label: {}, field: {}, show_errors: true)
|
62
|
+
# end
|
63
|
+
|
64
|
+
def submit(value = nil, options = {})
|
65
|
+
value, options = nil, value if value.is_a?(Hash)
|
66
|
+
options, defaults = split_defaults(options, class: "super-button")
|
67
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
68
|
+
|
69
|
+
@builder.submit(value, options)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Super
|
4
|
+
class FormBuilder
|
5
|
+
class Wrappers
|
6
|
+
def date_flatpickr(attribute, options = {})
|
7
|
+
options, defaults = split_defaults(
|
8
|
+
options,
|
9
|
+
class: "super-input w-full",
|
10
|
+
data: {
|
11
|
+
controller: "flatpickr",
|
12
|
+
flatpickr_options_value: {
|
13
|
+
dateFormat: "Y-m-d",
|
14
|
+
}
|
15
|
+
}
|
16
|
+
)
|
17
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
18
|
+
options[:data] = defaults[:data].deep_merge(options[:data] || {})
|
19
|
+
options[:value] = @builder.object.public_send(attribute).presence
|
20
|
+
options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
|
21
|
+
|
22
|
+
@builder.text_field(attribute, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
define_convenience :date_flatpickr
|
26
|
+
|
27
|
+
def datetime_flatpickr(attribute, options = {})
|
28
|
+
options, defaults = split_defaults(
|
29
|
+
options,
|
30
|
+
class: "super-input w-full",
|
31
|
+
data: {
|
32
|
+
controller: "flatpickr",
|
33
|
+
flatpickr_options_value: {
|
34
|
+
enableSeconds: true,
|
35
|
+
enableTime: true,
|
36
|
+
dateFormat: "Z",
|
37
|
+
}
|
38
|
+
}
|
39
|
+
)
|
40
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
41
|
+
options[:data] = defaults[:data].deep_merge(options[:data] || {})
|
42
|
+
options[:value] = @builder.object.public_send(attribute).presence
|
43
|
+
options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
|
44
|
+
|
45
|
+
@builder.text_field(attribute, options)
|
46
|
+
end
|
47
|
+
|
48
|
+
define_convenience :datetime_flatpickr
|
49
|
+
|
50
|
+
def time_flatpickr(attribute, options = {})
|
51
|
+
options, defaults = split_defaults(
|
52
|
+
options,
|
53
|
+
class: "super-input w-full",
|
54
|
+
data: {
|
55
|
+
controller: "flatpickr",
|
56
|
+
flatpickr_options_value: {
|
57
|
+
enableSeconds: true,
|
58
|
+
enableTime: true,
|
59
|
+
noCalendar: true,
|
60
|
+
dateFormat: "H:i:S",
|
61
|
+
}
|
62
|
+
}
|
63
|
+
)
|
64
|
+
options[:class] = join_classes(defaults[:class], options[:class])
|
65
|
+
options[:data] = defaults[:data].deep_merge(options[:data] || {})
|
66
|
+
options[:value] = @builder.object.public_send(attribute).presence
|
67
|
+
options[:value] = options[:value].strftime("%H:%M:%S") if options[:value].respond_to?(:strftime)
|
68
|
+
|
69
|
+
@builder.text_field(attribute, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
define_convenience :time_flatpickr
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Super
|
4
|
+
class FormBuilder
|
5
|
+
class Wrappers
|
6
|
+
def select(attribute, choices, options = {}, html_options = {}, &block)
|
7
|
+
options, defaults = split_defaults(options, include_blank: true)
|
8
|
+
options = defaults.merge(options)
|
9
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
10
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
11
|
+
|
12
|
+
@builder.select(attribute, choices, options, html_options, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
define_convenience :select
|
16
|
+
|
17
|
+
def collection_select(attribute, collection, value_method, text_method, options = {}, html_options = {})
|
18
|
+
options, defaults = split_defaults(options, include_blank: true)
|
19
|
+
options = defaults.merge(options)
|
20
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
21
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
22
|
+
|
23
|
+
@builder.collection_select(attribute, collection, value_method, text_method, options, html_options)
|
24
|
+
end
|
25
|
+
|
26
|
+
define_convenience :collection_select
|
27
|
+
|
28
|
+
def grouped_collection_select(attribute, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
29
|
+
options, defaults = split_defaults(options, include_blank: true)
|
30
|
+
options = defaults.merge(options)
|
31
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
32
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
33
|
+
|
34
|
+
@builder.grouped_collection_select(attribute, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
35
|
+
end
|
36
|
+
|
37
|
+
define_convenience :grouped_collection_select
|
38
|
+
|
39
|
+
def time_zone_select(attribute, priority_zones = nil, options = {}, html_options = {})
|
40
|
+
options, defaults = split_defaults(options, include_blank: true)
|
41
|
+
options = defaults.merge(options)
|
42
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
43
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
44
|
+
|
45
|
+
@builder.time_zone_select(attribute, priority_zones, options, html_options)
|
46
|
+
end
|
47
|
+
|
48
|
+
define_convenience :time_zone_select, priority_zones: "nil"
|
49
|
+
|
50
|
+
def collection_check_boxes(attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
51
|
+
options, defaults = split_defaults(options, include_blank: true)
|
52
|
+
options = defaults.merge(options)
|
53
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
54
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
55
|
+
|
56
|
+
@builder.collection_check_boxes(attribute, collection, value_method, text_method, options, html_options, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
define_convenience :collection_check_boxes
|
60
|
+
|
61
|
+
def collection_radio_buttons(attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
62
|
+
options, defaults = split_defaults(options, include_blank: true)
|
63
|
+
options = defaults.merge(options)
|
64
|
+
html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
|
65
|
+
html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
|
66
|
+
|
67
|
+
@builder.collection_radio_buttons(attribute, collection, value_method, text_method, options, html_options, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
define_convenience :collection_radio_buttons
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Super
|
4
|
+
# Example
|
5
|
+
#
|
6
|
+
# ```ruby
|
7
|
+
# super_form_for([:admin, @member]) do |f|
|
8
|
+
# # the long way
|
9
|
+
# f.super.label :name
|
10
|
+
# f.super.text_field :name
|
11
|
+
# f.super.inline_errors :name
|
12
|
+
#
|
13
|
+
# # the short way (slightly different from the long way, for alignment)
|
14
|
+
# f.super.text_field! :position
|
15
|
+
# end
|
16
|
+
# ```
|
17
|
+
#
|
18
|
+
# Refer to the Rails docs:
|
19
|
+
# https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
|
20
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
21
|
+
FIELD_ERROR_PROC = proc { |html_tag, instance| html_tag }
|
22
|
+
FORM_BUILDER_DEFAULTS = { builder: self }.freeze
|
23
|
+
|
24
|
+
def super(**options)
|
25
|
+
@super_wrappers ||= Wrappers.new(self, @template)
|
26
|
+
end
|
27
|
+
|
28
|
+
class Wrappers
|
29
|
+
def initialize(builder, template)
|
30
|
+
@builder = builder
|
31
|
+
@template = template
|
32
|
+
end
|
33
|
+
|
34
|
+
def inline_errors(attribute)
|
35
|
+
if @builder.object
|
36
|
+
messages = Form::InlineErrors.error_messages(@builder.object, attribute).map do |msg|
|
37
|
+
error_content_tag(msg)
|
38
|
+
end
|
39
|
+
|
40
|
+
@template.safe_join(messages)
|
41
|
+
else
|
42
|
+
error_content_tag(<<~MSG.html_safe)
|
43
|
+
This form doesn't have an object, so something is probably wrong.
|
44
|
+
Maybe <code>accepts_nested_attributes_for</code> isn't set up?
|
45
|
+
MSG
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def container(&block)
|
50
|
+
@template.content_tag(:div, class: "super-field-group", &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
private_class_method def self.define_with_label_tag(method_name, **optionals)
|
56
|
+
parameters = instance_method(method_name).parameters
|
57
|
+
definition = []
|
58
|
+
call = []
|
59
|
+
definition_last = ["label_text: nil", "label: {}", "show_errors: true"]
|
60
|
+
call_last = []
|
61
|
+
parameters.each do |type, name|
|
62
|
+
if name == :options && type == :opt
|
63
|
+
definition.push("field: {}")
|
64
|
+
call.push("field")
|
65
|
+
elsif name == :html_options && type == :opt
|
66
|
+
definition.push("field_html: {}")
|
67
|
+
call.push("field_html")
|
68
|
+
elsif type == :block
|
69
|
+
definition_last.push("&#{name}")
|
70
|
+
call_last.push("&#{name}")
|
71
|
+
else
|
72
|
+
if type == :req
|
73
|
+
definition.push(name.to_s)
|
74
|
+
call.push(name.to_s)
|
75
|
+
elsif type == :opt || type == :key
|
76
|
+
if !optionals.key?(name)
|
77
|
+
raise Super::Error::ArgumentError, "Form bang method has optional argument, but doesn't know the default value: #{name}"
|
78
|
+
end
|
79
|
+
|
80
|
+
default_value = optionals[name]
|
81
|
+
|
82
|
+
if type == :opt
|
83
|
+
definition.push("#{name} = #{default_value}")
|
84
|
+
call.push(name.to_s)
|
85
|
+
elsif type == :key
|
86
|
+
definition.push("#{name}: #{default_value}")
|
87
|
+
call.push("#{name}: #{name}")
|
88
|
+
else
|
89
|
+
raise Super::Error::ArgumentError, "Form bang method has a unprocessable argument with name #{name}"
|
90
|
+
end
|
91
|
+
else
|
92
|
+
raise Super::Error::ArgumentError, "Form bang method has keyword argument type #{type} and name #{name}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
definition += definition_last
|
98
|
+
call += call_last
|
99
|
+
|
100
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
101
|
+
def #{method_name}!(#{definition.join(", ")})
|
102
|
+
container do
|
103
|
+
compact_join([
|
104
|
+
public_send(:label, attribute, label_text, label),
|
105
|
+
%(<div class="mt-1">).html_safe,
|
106
|
+
#{method_name}(#{call.join(", ")}),
|
107
|
+
show_errors && inline_errors(attribute),
|
108
|
+
%(</div>).html_safe,
|
109
|
+
])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
RUBY
|
113
|
+
end
|
114
|
+
|
115
|
+
private_class_method def self.define_convenience(method_name, *args, **kwargs)
|
116
|
+
define_with_label_tag(method_name, *args, **kwargs)
|
117
|
+
::Super::Form::SchemaTypes.define_schema_type_for(method_name)
|
118
|
+
end
|
119
|
+
|
120
|
+
def split_defaults(options, **internal_defaults)
|
121
|
+
defaults = options.delete(:super) || {}
|
122
|
+
# prefer options set in `defaults`, since they are user overrides
|
123
|
+
defaults = internal_defaults.merge(defaults)
|
124
|
+
|
125
|
+
[options, defaults]
|
126
|
+
end
|
127
|
+
|
128
|
+
def join_classes(*class_lists)
|
129
|
+
class_lists.flatten.map(&:presence).compact
|
130
|
+
end
|
131
|
+
|
132
|
+
def error_content_tag(content)
|
133
|
+
@template.content_tag(:p, content, class: "text-red-400 text-xs italic pt-1")
|
134
|
+
end
|
135
|
+
|
136
|
+
def compact_join(*parts)
|
137
|
+
@template.safe_join(
|
138
|
+
parts.flatten.map(&:presence).compact
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/super/link.rb
CHANGED
@@ -9,75 +9,43 @@ module Super
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.find(link)
|
12
|
-
if link.kind_of?(self)
|
13
|
-
return link
|
14
|
-
end
|
15
|
-
|
16
12
|
if registry.key?(link)
|
17
|
-
|
13
|
+
found = registry[link]
|
14
|
+
|
15
|
+
if found.is_a?(LinkBuilder)
|
16
|
+
return found.dup
|
17
|
+
else
|
18
|
+
return found
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
raise Error::LinkNotRegistered, "Unknown link `#{link}`"
|
21
23
|
end
|
22
24
|
|
23
25
|
def self.registry
|
24
|
-
@registry ||= {
|
25
|
-
new
|
26
|
-
"
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
-> (record:, params:) {
|
48
|
-
{
|
49
|
-
controller: params[:controller],
|
50
|
-
action: :show,
|
51
|
-
id: record,
|
52
|
-
only_path: true
|
53
|
-
}
|
54
|
-
}
|
55
|
-
),
|
56
|
-
edit: LinkBuilder.new(
|
57
|
-
"Edit",
|
58
|
-
-> (record:, params:) {
|
59
|
-
{
|
60
|
-
controller: params[:controller],
|
61
|
-
action: :edit,
|
62
|
-
id: record,
|
63
|
-
only_path: true
|
64
|
-
}
|
65
|
-
}
|
66
|
-
),
|
67
|
-
destroy: LinkBuilder.new(
|
68
|
-
"Delete",
|
69
|
-
-> (record:, params:) {
|
70
|
-
{
|
71
|
-
controller: params[:controller],
|
72
|
-
action: :destroy,
|
73
|
-
id: record,
|
74
|
-
only_path: true
|
75
|
-
}
|
76
|
-
},
|
77
|
-
method: :delete,
|
78
|
-
data: { confirm: "Really delete?" }
|
79
|
-
),
|
80
|
-
}
|
26
|
+
@registry ||= {}.tap do |reg|
|
27
|
+
reg[:new] = LinkBuilder.new
|
28
|
+
.text { |params:| Super::Useful::I19.i18n_with_fallback("super", params[:controller].split("/"), "actions.new") }
|
29
|
+
.href { |params:| { controller: params[:controller], action: :new, only_path: true } }
|
30
|
+
.freeze
|
31
|
+
reg[:index] = LinkBuilder.new
|
32
|
+
.text { |params:| Super::Useful::I19.i18n_with_fallback("super", params[:controller].split("/"), "actions.index") }
|
33
|
+
.href { |params:| { controller: params[:controller], action: :index, only_path: true } }
|
34
|
+
.freeze
|
35
|
+
reg[:show] = LinkBuilder.new
|
36
|
+
.text { |params:, **| Super::Useful::I19.i18n_with_fallback("super", params[:controller].split("/"), "actions.show") }
|
37
|
+
.href { |params:, record:| { controller: params[:controller], action: :show, id: record, only_path: true } }
|
38
|
+
.freeze
|
39
|
+
reg[:edit] = LinkBuilder.new
|
40
|
+
.text { |params:, **| Super::Useful::I19.i18n_with_fallback("super", params[:controller].split("/"), "actions.edit") }
|
41
|
+
.href { |params:, record:| { controller: params[:controller], action: :edit, id: record, only_path: true } }
|
42
|
+
.freeze
|
43
|
+
reg[:destroy] = LinkBuilder.new
|
44
|
+
.text { |params:, **| Super::Useful::I19.i18n_with_fallback("super", params[:controller].split("/"), "actions.destroy") }
|
45
|
+
.href { |params:, record:| { controller: params[:controller], action: :destroy, id: record, only_path: true } }
|
46
|
+
.options { |**| { method: :delete, data: { confirm: "Really delete?" } } }
|
47
|
+
.freeze
|
48
|
+
end
|
81
49
|
end
|
82
50
|
|
83
51
|
def self.polymorphic_parts(*parts_tail)
|
@@ -85,15 +53,31 @@ module Super
|
|
85
53
|
parts_head.map { |part| part.is_a?(String) ? part.to_sym : part } + parts_tail
|
86
54
|
end
|
87
55
|
|
56
|
+
# The first argument should be the text of the link. If it's an array,
|
57
|
+
# it'll send it directly into `I18n.t`
|
88
58
|
def initialize(text, href, **options)
|
89
59
|
@text = text
|
90
60
|
@href = href
|
91
61
|
@options = options
|
92
62
|
end
|
93
63
|
|
94
|
-
attr_reader :text
|
95
64
|
attr_reader :options
|
96
65
|
|
66
|
+
def text
|
67
|
+
if @text.is_a?(Array)
|
68
|
+
*head, tail = @text
|
69
|
+
if !tail.is_a?(Hash)
|
70
|
+
head.push(tail)
|
71
|
+
tail = {}
|
72
|
+
end
|
73
|
+
|
74
|
+
@text = I18n.t(*head, **tail)
|
75
|
+
return @text
|
76
|
+
end
|
77
|
+
|
78
|
+
@text
|
79
|
+
end
|
80
|
+
|
97
81
|
def href
|
98
82
|
if @href.is_a?(String)
|
99
83
|
return @href
|