super 0.17.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/assets/javascripts/super/application.js +1260 -117
- data/app/assets/stylesheets/super/application.css +90711 -90034
- data/app/controllers/super/application_controller.rb +34 -4
- data/app/controllers/super/substructure_controller.rb +125 -29
- data/app/helpers/super/form_builder_helper.rb +4 -4
- data/app/views/layouts/super/application.html.erb +1 -1
- data/app/views/super/application/_batch_button.html.erb +12 -0
- data/app/views/super/application/_batch_checkbox.csv.erb +1 -0
- data/app/views/super/application/_batch_checkbox.html.erb +9 -0
- data/app/views/super/application/_batch_form.html.erb +3 -0
- data/app/views/super/application/_collection_header.html.erb +7 -6
- data/app/views/super/application/_csv_button.html.erb +25 -0
- data/app/views/super/application/_display_actions.html.erb +2 -2
- data/app/views/super/application/_form.html.erb +1 -1
- data/app/views/super/application/_layout.html.erb +13 -14
- data/app/views/super/application/_link.html.erb +8 -0
- data/app/views/super/application/_member_header.html.erb +7 -7
- data/app/views/super/application/_pagination.html.erb +2 -4
- data/app/views/super/application/_site_footer.html.erb +1 -1
- data/app/views/super/application/_site_header.html.erb +4 -4
- data/app/views/super/application/_view_chain.html.erb +5 -0
- data/app/views/super/application/index.csv.erb +14 -0
- data/config/locales/en.yml +15 -1
- data/frontend/super-frontend/dist/application.css +90711 -90034
- data/frontend/super-frontend/dist/application.js +6512 -5379
- data/frontend/super-frontend/dist/package.json +13 -0
- data/lib/generators/super/webpacker/USAGE +1 -7
- data/lib/generators/super/webpacker/templates/pack_super_application.js.tt +2 -0
- data/lib/generators/super/webpacker/webpacker_generator.rb +10 -6
- data/lib/super/action_inquirer.rb +3 -0
- data/lib/super/cheat.rb +1 -0
- data/lib/super/display/schema_types.rb +6 -0
- data/lib/super/display.rb +2 -1
- data/lib/super/engine.rb +5 -0
- data/lib/super/error.rb +11 -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/layout.rb +9 -33
- data/lib/super/link.rb +49 -70
- data/lib/super/link_builder.rb +24 -47
- data/lib/super/packaged_asset.rb +49 -0
- data/lib/super/pagination.rb +2 -1
- data/lib/super/reorderable_hash.rb +88 -0
- data/lib/super/reset.rb +20 -1
- data/lib/super/useful/i19.rb +35 -0
- data/lib/super/version.rb +1 -1
- data/lib/super/view_chain.rb +25 -0
- data/lib/super.rb +9 -1
- metadata +55 -10
- data/lib/generators/super/webpacker/templates/pack_super_application.js.erb.tt +0 -2
- data/lib/super/form/builder.rb +0 -289
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"name": "@superadministration/super",
|
3
|
+
"description": "The frontend code for Super, a Rails admin framework",
|
4
|
+
"homepage": "https://github.com/superadministration/super",
|
5
|
+
"license": "LGPL-3.0-only",
|
6
|
+
"main": "application.js",
|
7
|
+
"files": [
|
8
|
+
"application.js",
|
9
|
+
"application.css",
|
10
|
+
"package.json"
|
11
|
+
],
|
12
|
+
"version": "0.20.0"
|
13
|
+
}
|
@@ -1,15 +1,9 @@
|
|
1
1
|
Description:
|
2
2
|
Creates the necessary files for assets to be served under Webpacker
|
3
3
|
|
4
|
-
Webpacker support requires that you install ERB support for Webpacker.
|
5
|
-
|
6
|
-
Installing ERB on webpacker is usually done by running the command:
|
7
|
-
`rails webpacker:install:erb`
|
8
|
-
|
9
4
|
Example:
|
10
|
-
rails webpacker:install:erb # if you hadn't set up ERB already
|
11
5
|
rails generate super:webpacker
|
12
6
|
|
13
7
|
This will:
|
14
|
-
Create app/javascript/packs/super/application.js
|
8
|
+
Create app/javascript/packs/super/application.js
|
15
9
|
Modify config/initializers/super.rb
|
@@ -7,12 +7,12 @@ module Super
|
|
7
7
|
def copy_the_pack_file
|
8
8
|
path =
|
9
9
|
if Gem::Dependency.new("webpacker", ">= 6.0.0.beta2", "!= 6.0.0.pre1", "!= 6.0.0.pre2").matching_specs.any?
|
10
|
-
"app/packs/entrypoints/super/application.js
|
10
|
+
"app/packs/entrypoints/super/application.js"
|
11
11
|
else
|
12
|
-
"app/javascript/packs/super/application.js
|
12
|
+
"app/javascript/packs/super/application.js"
|
13
13
|
end
|
14
14
|
|
15
|
-
template("pack_super_application.js
|
15
|
+
template("pack_super_application.js", path)
|
16
16
|
end
|
17
17
|
|
18
18
|
def set_asset_handler_to_webpacker
|
@@ -24,9 +24,13 @@ module Super
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
27
|
+
def install_via_yarn
|
28
|
+
super_root = Pathname.new(__dir__).join("../../../..")
|
29
|
+
if super_root.join("dummy_path.rb").file?
|
30
|
+
run "yarn add file:#{super_root.join("frontend/super-frontend/dist")}"
|
31
|
+
else
|
32
|
+
run "yarn add @superadministration/super@#{Super::VERSION} --exact"
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
data/lib/super/cheat.rb
CHANGED
@@ -8,6 +8,7 @@ module Super
|
|
8
8
|
paths
|
9
9
|
.map { |f| File.read(File.expand_path(f, __dir__)) }
|
10
10
|
.flat_map { |content| content.scan(/^\s+(?:helper_method )?def .*$/) }
|
11
|
+
.reject { |method| method =~ /\bdef self\./ }
|
11
12
|
.map { |method| method.strip.sub(/^(?:helper_method )?def /, "#") }
|
12
13
|
|
13
14
|
puts "== Super::ApplicationController"
|
@@ -129,6 +129,12 @@ module Super
|
|
129
129
|
real(:column, &transform_block)
|
130
130
|
end
|
131
131
|
|
132
|
+
def batch
|
133
|
+
real do |value|
|
134
|
+
Partial.new("batch_checkbox", locals: { value: value })
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
132
138
|
def string; real(&:to_s); end
|
133
139
|
|
134
140
|
def timestamp; real(&:to_s); end
|
data/lib/super/display.rb
CHANGED
@@ -32,10 +32,11 @@ module Super
|
|
32
32
|
yield(@fields, @schema_types)
|
33
33
|
end
|
34
34
|
|
35
|
-
def apply(action:)
|
35
|
+
def apply(action:, format:)
|
36
36
|
@action_inquirer = action
|
37
37
|
return self if !@action_inquirer.index?
|
38
38
|
return self if @schema_types.actions_called?
|
39
|
+
return self if !format.html?
|
39
40
|
@fields[:actions] = @schema_types.actions
|
40
41
|
self
|
41
42
|
end
|
data/lib/super/engine.rb
CHANGED
@@ -15,6 +15,11 @@ module Super
|
|
15
15
|
Super::Plugin::Registry.controller.ordered do |klass, method_name|
|
16
16
|
Super::ApplicationController.public_send(method_name, klass)
|
17
17
|
end
|
18
|
+
|
19
|
+
Super::PackagedAsset.warning_message =
|
20
|
+
if !Super::PackagedAsset.version_matches_gem?(Rails.root.join("package.json"))
|
21
|
+
I18n.t("super.mismatching_package_json_gemfile_versions")
|
22
|
+
end
|
18
23
|
end
|
19
24
|
end
|
20
25
|
end
|
data/lib/super/error.rb
CHANGED
@@ -30,11 +30,22 @@ module Super
|
|
30
30
|
class ArgumentError < Error; end
|
31
31
|
class AlreadyRegistered < Error; end
|
32
32
|
class AlreadyTranscribed < Error; end
|
33
|
+
class NotImplementedError < Error; end
|
34
|
+
class IncompleteBuilder < Error; end
|
33
35
|
|
34
36
|
class Enum < Error
|
35
37
|
class ImpossibleValue < Enum; end
|
36
38
|
class ArgumentError < Enum; end
|
37
39
|
class UndefinedCase < Enum; end
|
38
40
|
end
|
41
|
+
|
42
|
+
class ReorderableHash < Error
|
43
|
+
class DuplicateKey < ReorderableHash; end
|
44
|
+
class KeyError < ReorderableHash; end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ViewChain < Error
|
48
|
+
class ChainAlreadyStarted < ViewChain; end
|
49
|
+
end
|
39
50
|
end
|
40
51
|
end
|
@@ -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/layout.rb
CHANGED
@@ -6,44 +6,20 @@ module Super
|
|
6
6
|
class Layout
|
7
7
|
include Super::Partial::Resolving
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
9
|
+
def initialize(header: nil, aside: nil, main: nil, footer: nil)
|
10
|
+
@header = header
|
11
|
+
@aside = aside
|
12
|
+
@main = main
|
13
|
+
@footer = footer
|
14
14
|
end
|
15
15
|
|
16
|
-
attr_reader :
|
17
|
-
attr_reader :
|
18
|
-
attr_reader :
|
19
|
-
attr_reader :
|
16
|
+
attr_reader :header
|
17
|
+
attr_reader :aside
|
18
|
+
attr_reader :main
|
19
|
+
attr_reader :footer
|
20
20
|
|
21
21
|
def to_partial_path
|
22
22
|
"layout"
|
23
23
|
end
|
24
|
-
|
25
|
-
def resolve(template)
|
26
|
-
@resolved_headers = resolve_for_rendering(template, headers, nil)
|
27
|
-
@resolved_asides = resolve_for_rendering(template, asides, nil)
|
28
|
-
@resolved_mains = resolve_for_rendering(template, mains, nil)
|
29
|
-
@resolved_footers = resolve_for_rendering(template, footers, nil)
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def resolved_headers
|
34
|
-
@resolved_headers || []
|
35
|
-
end
|
36
|
-
|
37
|
-
def resolved_asides
|
38
|
-
@resolved_asides || []
|
39
|
-
end
|
40
|
-
|
41
|
-
def resolved_mains
|
42
|
-
@resolved_mains || []
|
43
|
-
end
|
44
|
-
|
45
|
-
def resolved_footers
|
46
|
-
@resolved_footers || []
|
47
|
-
end
|
48
24
|
end
|
49
25
|
end
|