compony 0.5.2 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile.lock +6 -6
  5. data/README.md +38 -0
  6. data/VERSION +1 -1
  7. data/app/controllers/compony_controller.rb +4 -0
  8. data/compony.gemspec +4 -4
  9. data/doc/ComponentGenerator.html +1 -1
  10. data/doc/Components.html +1 -1
  11. data/doc/ComponentsGenerator.html +1 -1
  12. data/doc/Compony/Component.html +1 -1
  13. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +96 -27
  16. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
  17. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  18. data/doc/Compony/ComponentMixins/Default.html +1 -1
  19. data/doc/Compony/ComponentMixins/Resourceful.html +1 -1
  20. data/doc/Compony/ComponentMixins.html +1 -1
  21. data/doc/Compony/Components/Button.html +9 -5
  22. data/doc/Compony/Components/Destroy.html +1 -1
  23. data/doc/Compony/Components/Edit.html +1 -1
  24. data/doc/Compony/Components/Form.html +289 -135
  25. data/doc/Compony/Components/New.html +1 -1
  26. data/doc/Compony/Components/WithForm.html +1 -1
  27. data/doc/Compony/Components.html +1 -1
  28. data/doc/Compony/ControllerMixin.html +1 -1
  29. data/doc/Compony/Engine.html +1 -1
  30. data/doc/Compony/MethodAccessibleHash.html +1 -1
  31. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  32. data/doc/Compony/ModelFields/Association.html +1 -1
  33. data/doc/Compony/ModelFields/Attachment.html +1 -1
  34. data/doc/Compony/ModelFields/Base.html +1 -1
  35. data/doc/Compony/ModelFields/Boolean.html +1 -1
  36. data/doc/Compony/ModelFields/Color.html +1 -1
  37. data/doc/Compony/ModelFields/Currency.html +1 -1
  38. data/doc/Compony/ModelFields/Date.html +1 -1
  39. data/doc/Compony/ModelFields/Datetime.html +1 -1
  40. data/doc/Compony/ModelFields/Decimal.html +1 -1
  41. data/doc/Compony/ModelFields/Email.html +1 -1
  42. data/doc/Compony/ModelFields/Float.html +1 -1
  43. data/doc/Compony/ModelFields/Integer.html +1 -1
  44. data/doc/Compony/ModelFields/Percentage.html +1 -1
  45. data/doc/Compony/ModelFields/Phone.html +1 -1
  46. data/doc/Compony/ModelFields/RichText.html +1 -1
  47. data/doc/Compony/ModelFields/String.html +1 -1
  48. data/doc/Compony/ModelFields/Text.html +1 -1
  49. data/doc/Compony/ModelFields/Time.html +1 -1
  50. data/doc/Compony/ModelFields/Url.html +1 -1
  51. data/doc/Compony/ModelFields.html +1 -1
  52. data/doc/Compony/ModelMixin.html +25 -25
  53. data/doc/Compony/NaturalOrdering.html +1 -1
  54. data/doc/Compony/RequestContext.html +1 -1
  55. data/doc/Compony/Version.html +1 -1
  56. data/doc/Compony/ViewHelpers.html +30 -12
  57. data/doc/Compony.html +4 -4
  58. data/doc/ComponyController.html +1 -1
  59. data/doc/_index.html +1 -1
  60. data/doc/file.README.html +39 -1
  61. data/doc/index.html +39 -1
  62. data/doc/method_list.html +65 -41
  63. data/doc/top-level-namespace.html +1 -1
  64. data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +18 -10
  65. data/lib/compony/components/button.rb +5 -3
  66. data/lib/compony/components/form.rb +57 -32
  67. data/lib/compony/model_mixin.rb +19 -13
  68. data/lib/compony/view_helpers.rb +12 -4
  69. data/lib/compony.rb +3 -3
  70. metadata +3 -9
@@ -7,7 +7,7 @@ module Compony
7
7
 
8
8
  # path: If given a block, it will be evaluated in the helpers context when rendering
9
9
  # enabled: If given a block, it will be evaluated in the helpers context when rendering
10
- def initialize(*, label: nil, path: nil, method: nil, type: nil, enabled: nil, visible: nil, title: nil, **, &)
10
+ def initialize(*, label: nil, path: nil, method: nil, type: nil, enabled: nil, visible: nil, title: nil, button_params: nil, value: nil, **, &)
11
11
  @label = label || Compony.button_defaults[:label]
12
12
  @type = type&.to_sym || Compony.button_defaults[:type] || :button
13
13
  @path = path || Compony.button_defaults[:path] || 'javascript:void(0)'
@@ -23,6 +23,8 @@ module Compony
23
23
  @visible = Compony.button_defaults[:visible] if @visible.nil?
24
24
  @visible = true if @visible.nil?
25
25
  @title = title || Compony.button_defaults[:title]
26
+ @button_params = button_params
27
+ @value = value
26
28
 
27
29
  fail "Unsupported button type #{@type}, use on of: #{SUPPORTED_TYPES.inspect}" unless SUPPORTED_TYPES.include?(@type)
28
30
 
@@ -47,9 +49,9 @@ module Compony
47
49
  if @visible
48
50
  case @type
49
51
  when :button
50
- concat button_to(@label, @path, method: @method, disabled: !@enabled, title: @title)
52
+ concat button_to(@label, @path, method: @method, disabled: !@enabled, title: @title, params: @button_params)
51
53
  when :submit
52
- concat button_tag(@label, type: :submit, disabled: !@enabled, title: @title)
54
+ concat button_tag(@label, type: :submit, disabled: !@enabled, title: @title, value: @value)
53
55
  end
54
56
  end
55
57
  end
@@ -3,9 +3,10 @@ module Compony
3
3
  # @api description
4
4
  # This component is used for the _form partial in the Rails paradigm.
5
5
  class Form < Component
6
- def initialize(*args, cancancan_action: :missing, **kwargs)
6
+ def initialize(*args, cancancan_action: :missing, disabled: false, **kwargs)
7
7
  @schema_lines_for_data = [] # Array of procs taking data returning a Schemacop proc
8
8
  @cancancan_action = cancancan_action
9
+ @form_disabled = disabled
9
10
  super
10
11
  end
11
12
 
@@ -35,7 +36,8 @@ module Compony
35
36
  end
36
37
 
37
38
  content do
38
- form_html = simple_form_for(data, method: @comp_opts[:submit_verb], url: @submit_path) do |f|
39
+ form_params = { method: @comp_opts[:submit_verb], url: @submit_path }.merge(@form_params || {})
40
+ form_html = simple_form_for(data, **form_params) do |f|
39
41
  component.with_simpleform(f, controller) do
40
42
  instance_exec(&form_fields)
41
43
  div class: 'compony-form-buttons' do
@@ -94,30 +96,38 @@ module Compony
94
96
 
95
97
  # Called inside the form_fields block. This makes the method `field` available in the block.
96
98
  # See also notes for `with_simpleform`.
97
- def field(name, **input_opts)
99
+ # If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility"). Render the array as you wish.
100
+ def field(name, multilang: false, **input_opts)
98
101
  fail("The `field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform
99
- name = name.to_sym
100
102
 
101
- # Check per-field authorization
102
- if @cancancan_action.present? && @controller.current_ability.permitted_attributes(@cancancan_action, @simpleform.object).exclude?(name)
103
- Rails.logger.debug do
104
- "Skipping form field #{name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{@simpleform.object}."
103
+ if multilang
104
+ I18n.available_locales.map { |locale| field("#{name}_#{locale}", **input_opts) }
105
+ else
106
+ name = name.to_sym
107
+
108
+ input_opts.merge!(disabled: true) if @form_disabled
109
+
110
+ # Check per-field authorization
111
+ if @cancancan_action.present? && @controller.current_ability.permitted_attributes(@cancancan_action, @simpleform.object).exclude?(name)
112
+ Rails.logger.debug do
113
+ "Skipping form field #{name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{@simpleform.object}."
114
+ end
115
+ return
105
116
  end
106
- return
107
- end
108
117
 
109
- hidden = input_opts.delete(:hidden)
110
- model_field = @simpleform.object.fields[name]
111
- fail("Field #{name.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field
118
+ hidden = input_opts.delete(:hidden)
119
+ model_field = @simpleform.object.fields[name]
120
+ fail("Field #{name.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field
112
121
 
113
- if hidden
114
- return model_field.simpleform_input_hidden(@simpleform, self, **input_opts)
115
- else
116
- unless @focus_given || @skip_autofocus
117
- input_opts[:autofocus] = true unless input_opts.key? :autofocus
118
- @focus_given = true
122
+ if hidden
123
+ return model_field.simpleform_input_hidden(@simpleform, self, **input_opts)
124
+ else
125
+ unless @focus_given || @skip_autofocus
126
+ input_opts[:autofocus] = true unless input_opts.key? :autofocus
127
+ @focus_given = true
128
+ end
129
+ return model_field.simpleform_input(@simpleform, self, **input_opts)
119
130
  end
120
- return model_field.simpleform_input(@simpleform, self, **input_opts)
121
131
  end
122
132
  end
123
133
 
@@ -155,6 +165,16 @@ module Compony
155
165
  Compony::ModelFields::Anchormodel.collect(...)
156
166
  end
157
167
 
168
+ # DSL method, disables all inputs
169
+ def disable!
170
+ @form_disabled = true
171
+ end
172
+
173
+ # DSL method, allows to customize parameters given to simple_form_for
174
+ def form_params(**new_form_params)
175
+ @form_params = new_form_params
176
+ end
177
+
158
178
  protected
159
179
 
160
180
  # DSL method, adds a new line to the schema whitelisting a single param inside the schema's wrapper
@@ -165,19 +185,24 @@ module Compony
165
185
 
166
186
  # DSL method, adds a new field to the schema whitelisting a single field of data_class
167
187
  # This auto-generates the correct schema line for the field.
168
- def schema_field(field_name)
169
- # This runs upon component setup.
170
- @schema_lines_for_data << proc do |data, controller|
171
- # This runs within a request context.
172
- field = data.class.fields[field_name.to_sym] || fail("No field #{field_name.to_sym.inspect} found for #{data.inspect} in #{inspect}.")
173
- # Check per-field authorization
174
- if @cancancan_action.present? && controller.current_ability.permitted_attributes(@cancancan_action.to_sym, data).exclude?(field.name.to_sym)
175
- Rails.logger.debug do
176
- "Skipping form schema_field #{field_name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{data}."
188
+ # If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility")
189
+ def schema_field(field_name, multilang: false)
190
+ if multilang
191
+ I18n.available_locales.each { |locale| schema_field("#{field_name}_#{locale}") }
192
+ else
193
+ # This runs upon component setup.
194
+ @schema_lines_for_data << proc do |data, controller|
195
+ # This runs within a request context.
196
+ field = data.class.fields[field_name.to_sym] || fail("No field #{field_name.to_sym.inspect} found for #{data.inspect} in #{inspect}.")
197
+ # Check per-field authorization
198
+ if @cancancan_action.present? && controller.current_ability.permitted_attributes(@cancancan_action.to_sym, data).exclude?(field.name.to_sym)
199
+ Rails.logger.debug do
200
+ "Skipping form schema_field #{field_name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{data}."
201
+ end
202
+ next nil
177
203
  end
178
- next nil
204
+ next field.schema_line
179
205
  end
180
- next field.schema_line
181
206
  end
182
207
  end
183
208
 
@@ -190,7 +215,7 @@ module Compony
190
215
  # Check per-field authorization
191
216
  unless @cancancan_action.nil? || controller.current_ability.can?(:set_password, data)
192
217
  Rails.logger.debug do
193
- "Skipping form schema_pw_field #{name.inspect} because the current user is not allowed to perform :set_password on #{data}."
218
+ "Skipping form schema_pw_field #{field_name.inspect} because the current user is not allowed to perform :set_password on #{data}."
194
219
  end
195
220
  next nil
196
221
  end
@@ -19,21 +19,27 @@ module Compony
19
19
  end
20
20
 
21
21
  # DSL method, defines a new field which will be translated and can be added to field groups
22
- def field(name, type, **extra_attrs)
23
- name = name.to_sym
24
- self.fields = fields.dup
25
- field = Compony.model_field_class_for(type.to_s.camelize).new(name, self, **extra_attrs)
26
- # Handle the case where ActiveType would interfere with attribute registration
27
- if defined?(ActiveType) && self <= ActiveType::Object && !include?(ActiveModel::Attributes)
28
- fail "Please add `include ActiveModel::Attributes` at the top of the class #{self}, as attributes cannot be registered otherwise with ActiveType."
29
- end
30
- # Register the field as an attribute
31
- if defined?(ActiveType) && self <= ActiveType::Object
32
- ar_attribute(name)
22
+ # If multilang is true, a suffixed field is generated for every available locale, along with a non-suffixed virtual field (useful with gem "mobility")
23
+ def field(name, type, multilang: false, **extra_attrs)
24
+ if multilang
25
+ field(name, type, virtual: true, **extra_attrs)
26
+ I18n.available_locales.each { |locale| field("#{name}_#{locale}", type, **extra_attrs) }
33
27
  else
34
- attribute(name)
28
+ name = name.to_sym
29
+ self.fields = fields.dup
30
+ field = Compony.model_field_class_for(type.to_s.camelize).new(name, self, **extra_attrs)
31
+ # Handle the case where ActiveType would interfere with attribute registration
32
+ if defined?(ActiveType) && self <= ActiveType::Object && !include?(ActiveModel::Attributes)
33
+ fail "Please add `include ActiveModel::Attributes` at the top of the class #{self}, as attributes cannot be registered otherwise with ActiveType."
34
+ end
35
+ # Register the field as an attribute
36
+ if defined?(ActiveType) && self <= ActiveType::Object
37
+ ar_attribute(name)
38
+ else
39
+ attribute(name)
40
+ end
41
+ fields[name] = field
35
42
  end
36
- fields[name] = field
37
43
  end
38
44
 
39
45
  # DSL method, sets the containing model.
@@ -19,11 +19,19 @@ module Compony
19
19
  # @param link_args [Array] Positional arguments that will be passed to the Rails `link_to` helper
20
20
  # @param label_opts [Hash] Options hash that will be passed to the label method (see {Compony::ComponentMixins::Default::Labelling#label})
21
21
  # @param link_kwargs [Hash] Named arguments that will be passed to the Rails `link_to` helper
22
- def compony_link(comp_name_or_cst, model_or_family_name_or_cst, *link_args, label_opts: {}, **link_kwargs)
22
+ def compony_link(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil, *link_args, label_opts: {}, params: {}, standalone_name: nil, **link_kwargs)
23
23
  model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil
24
- comp = Compony.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst).new(data: model)
25
- return unless comp.standalone_access_permitted_for?(self)
26
- return helpers.link_to(comp.label(model, **label_opts), Compony.path(comp.comp_name, comp.family_name, model), *link_args, **link_kwargs)
24
+ if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
25
+ target_comp_instance = comp_name_or_cst_or_class.new(data: model)
26
+ else
27
+ target_comp_instance = Compony.comp_class_for!(comp_name_or_cst_or_class, model_or_family_name_or_cst).new(data: model)
28
+ end
29
+ return unless target_comp_instance.standalone_access_permitted_for?(self, standalone_name:)
30
+ return helpers.link_to(
31
+ target_comp_instance.label(model, **label_opts),
32
+ Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params),
33
+ *link_args, **link_kwargs
34
+ )
27
35
  end
28
36
 
29
37
  # Given a component and a family/model, this instanciates and renders a button component.
data/lib/compony.rb CHANGED
@@ -79,13 +79,13 @@ module Compony
79
79
  end
80
80
 
81
81
  # Getter for content_before_root_comp_block
82
- # @see Compony#content_before_root_comp
82
+ # @see Compony#content_before_root_comp=
83
83
  def self.content_before_root_comp_block
84
84
  @content_before_root_comp_block
85
85
  end
86
86
 
87
87
  # Getter for content_after_root_comp_block
88
- # @see Compony#content_after_root_comp
88
+ # @see Compony#content_after_root_comp=
89
89
  def self.content_after_root_comp_block
90
90
  @content_after_root_comp_block
91
91
  end
@@ -198,7 +198,7 @@ module Compony
198
198
  color: target_comp_instance.color,
199
199
  path: Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params),
200
200
  method:,
201
- visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, verb: method) }
201
+ visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, standalone_name:, verb: method) }
202
202
  }
203
203
  if feasibility_target
204
204
  options.merge!({
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
8
8
  - contributors
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-11-20 00:00:00.000000000 Z
11
+ date: 2025-02-14 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: yard
@@ -165,8 +164,6 @@ dependencies:
165
164
  - - "~>"
166
165
  - !ruby/object:Gem::Version
167
166
  version: 3.6.1
168
- description:
169
- email:
170
167
  executables: []
171
168
  extensions: []
172
169
  extra_rdoc_files: []
@@ -312,10 +309,8 @@ files:
312
309
  - lib/generators/components/USAGE
313
310
  - lib/generators/components/components_generator.rb
314
311
  - logo.svg
315
- homepage:
316
312
  licenses: []
317
313
  metadata: {}
318
- post_install_message:
319
314
  rdoc_options: []
320
315
  require_paths:
321
316
  - lib
@@ -330,8 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
330
325
  - !ruby/object:Gem::Version
331
326
  version: '0'
332
327
  requirements: []
333
- rubygems_version: 3.5.22
334
- signing_key:
328
+ rubygems_version: 3.6.3
335
329
  specification_version: 4
336
330
  summary: Compony is a Gem that allows you to write your Rails application in component-style
337
331
  fashion. It combines a controller action and route along \ with its view into a