abyme 0.5.1 → 0.6.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/.DS_Store +0 -0
- data/.babelrc +6 -0
- data/Gemfile.lock +91 -84
- data/README.md +5 -5
- data/abyme.gemspec +4 -2
- data/dist/abyme.js +2 -0
- data/dist/abyme.js.map +1 -0
- data/dist/abyme.modern.js +2 -0
- data/dist/abyme.modern.js.map +1 -0
- data/dist/abyme.module.js +2 -0
- data/dist/abyme.module.js.map +1 -0
- data/dist/abyme.umd.js +2 -0
- data/dist/abyme.umd.js.map +1 -0
- data/jest/jest-setup.js +2 -0
- data/lib/abyme/abyme_builder.rb +6 -8
- data/lib/abyme/version.rb +2 -2
- data/lib/abyme/view_helpers.rb +53 -51
- data/lib/generators/abyme/controller/USAGE +16 -0
- data/lib/generators/abyme/controller/controller_generator.rb +25 -0
- data/lib/generators/abyme/model/USAGE +21 -0
- data/lib/generators/abyme/model/model_generator.rb +70 -0
- data/lib/generators/abyme/resource/USAGE +10 -0
- data/lib/generators/abyme/resource/resource_generator.rb +18 -0
- data/lib/generators/abyme/stimulus/USAGE +5 -0
- data/lib/generators/abyme/stimulus/stimulus_generator.rb +21 -0
- data/lib/generators/abyme/view/view_generator.rb +65 -0
- data/package-lock.json +31992 -0
- data/package.json +34 -4
- data/specs/index.test.js +26 -0
- data/{javascript → src}/abyme_controller.js +1 -3
- data/{javascript → src}/index.js +0 -0
- data/yarn.lock +8228 -24
- metadata +54 -5
data/lib/abyme/version.rb
CHANGED
data/lib/abyme/view_helpers.rb
CHANGED
@@ -2,7 +2,6 @@ require_relative "abyme_builder"
|
|
2
2
|
|
3
3
|
module Abyme
|
4
4
|
module ViewHelpers
|
5
|
-
|
6
5
|
# ABYME_FOR
|
7
6
|
|
8
7
|
# this helper will generate the top level wrapper markup
|
@@ -23,7 +22,7 @@ module Abyme
|
|
23
22
|
# set the default number of blank fields to display
|
24
23
|
|
25
24
|
# - partial (String)
|
26
|
-
# to customize the partial path by default #abyme_for will expect
|
25
|
+
# to customize the partial path by default #abyme_for will expect
|
27
26
|
# a partial to bbe present in views/abyme
|
28
27
|
|
29
28
|
# - Exemple
|
@@ -39,22 +38,24 @@ module Abyme
|
|
39
38
|
# </div>
|
40
39
|
|
41
40
|
def abyme_for(association, form, options = {}, &block)
|
42
|
-
content_tag(:div, data: {
|
43
|
-
if
|
44
|
-
yield(
|
45
|
-
|
41
|
+
content_tag(:div, data: {controller: "abyme", limit: options[:limit], min_count: options[:min_count]}, id: "abyme--#{association}") do
|
42
|
+
if block
|
43
|
+
yield(
|
44
|
+
Abyme::AbymeBuilder.new(
|
45
|
+
association: association, form: form, context: self, partial: options[:partial]
|
46
46
|
)
|
47
47
|
)
|
48
48
|
else
|
49
|
-
model = association.to_s.singularize.classify.constantize
|
49
|
+
# model = association.to_s.singularize.classify.constantize
|
50
|
+
model = association.to_s.singularize
|
50
51
|
concat(persisted_records_for(association, form, options))
|
51
|
-
concat(new_records_for(association, form, options))
|
52
|
+
concat(new_records_for(association, form, options))
|
52
53
|
concat(add_associated_record(content: options[:button_text] || "Add #{model}"))
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
alias_method :abymize, :abyme_for
|
58
59
|
|
59
60
|
# NEW_RECORDS_FOR
|
60
61
|
|
@@ -72,9 +73,9 @@ module Abyme
|
|
72
73
|
# will output this html
|
73
74
|
|
74
75
|
# <div data-target="abyme.associations" data-association="tasks" data-abyme-position="end">
|
75
|
-
# <template class="abyme--task_template" data-target="abyme.template">
|
76
|
+
# <template class="abyme--task_template" data-target="abyme.template">
|
76
77
|
# <div data-target="abyme.fields abyme.newFields" class="abyme--fields task-fields">
|
77
|
-
# ... partial html goes here
|
78
|
+
# ... partial html goes here
|
78
79
|
# </div>
|
79
80
|
# </template>
|
80
81
|
# ... new rendered fields goes here
|
@@ -82,41 +83,41 @@ module Abyme
|
|
82
83
|
|
83
84
|
# == Options
|
84
85
|
# - position (:start, :end)
|
85
|
-
# allows you to specify whether new fields added dynamically
|
86
|
-
# should go at the top or at the bottom
|
86
|
+
# allows you to specify whether new fields added dynamically
|
87
|
+
# should go at the top or at the bottom
|
87
88
|
# :end is the default value
|
88
89
|
|
89
90
|
# - partial (String)
|
90
|
-
# to customize the partial path by default #abyme_for will expect
|
91
|
+
# to customize the partial path by default #abyme_for will expect
|
91
92
|
# a partial to bbe present in views/abyme
|
92
93
|
|
93
94
|
# - fields_html (Hash)
|
94
95
|
# allows you to pass any html attributes to each fields wrapper
|
95
96
|
|
96
97
|
# - wrapper_html (Hash)
|
97
|
-
# allows you to pass any html attributes to the the html element
|
98
|
+
# allows you to pass any html attributes to the the html element
|
98
99
|
# wrapping all the fields
|
99
100
|
|
100
101
|
def new_records_for(association, form, options = {}, &block)
|
101
102
|
options[:wrapper_html] ||= {}
|
102
103
|
|
103
|
-
wrapper_default = {
|
104
|
-
data: {
|
105
|
-
abyme_target:
|
106
|
-
association: association,
|
107
|
-
abyme_position: options[:position] || :end
|
108
|
-
}
|
104
|
+
wrapper_default = {
|
105
|
+
data: {
|
106
|
+
abyme_target: "associations",
|
107
|
+
association: association,
|
108
|
+
abyme_position: options[:position] || :end
|
109
|
+
}
|
109
110
|
}
|
110
111
|
|
111
|
-
fields_default = {
|
112
|
+
fields_default = {data: {target: "abyme.fields abyme.newFields"}}
|
112
113
|
|
113
114
|
content_tag(:div, build_attributes(wrapper_default, options[:wrapper_html])) do
|
114
|
-
content_tag(:template, class: "abyme--#{association.to_s.singularize}_template", data: {
|
115
|
-
form.fields_for association, association.to_s.classify.constantize.new, child_index:
|
115
|
+
content_tag(:template, class: "abyme--#{association.to_s.singularize}_template", data: {abyme_target: "template"}) do
|
116
|
+
form.fields_for association, association.to_s.classify.constantize.new, child_index: "NEW_RECORD" do |f|
|
116
117
|
content_tag(:div, build_attributes(fields_default, basic_fields_markup(options[:fields_html], association))) do
|
117
118
|
# Here, if a block is passed, we're passing the association fields to it, rather than the form itself
|
118
119
|
# block_given? ? yield(f) : render(options[:partial] || "abyme/#{association.to_s.singularize}_fields", f: f)
|
119
|
-
|
120
|
+
block ? yield(f) : render_association_partial(association, f, options[:partial])
|
120
121
|
end
|
121
122
|
end
|
122
123
|
end
|
@@ -154,21 +155,23 @@ module Abyme
|
|
154
155
|
# ex: order: { created_at: :desc }
|
155
156
|
|
156
157
|
# - partial (String)
|
157
|
-
# to customize the partial path by default #abyme_for will expect
|
158
|
+
# to customize the partial path by default #abyme_for will expect
|
158
159
|
# a partial to bbe present in views/abyme
|
159
160
|
|
160
161
|
# - fields_html (Hash)
|
161
162
|
# allows you to pass any html attributes to each fields wrapper
|
162
163
|
|
163
164
|
# - wrapper_html (Hash)
|
164
|
-
# allows you to pass any html attributes to the the html element
|
165
|
+
# allows you to pass any html attributes to the the html element
|
165
166
|
# wrapping all the fields
|
166
|
-
|
167
|
+
|
167
168
|
def persisted_records_for(association, form, options = {})
|
168
169
|
records = options[:collection] || form.object.send(association)
|
170
|
+
# return if records.empty?
|
171
|
+
|
169
172
|
options[:wrapper_html] ||= {}
|
170
|
-
fields_default = {
|
171
|
-
|
173
|
+
fields_default = {data: {abyme_target: "fields"}}
|
174
|
+
|
172
175
|
if options[:order].present?
|
173
176
|
records = records.order(options[:order])
|
174
177
|
# by calling the order method on the AR collection
|
@@ -176,8 +179,8 @@ module Abyme
|
|
176
179
|
# so we have to get them back with the 2 lines below
|
177
180
|
invalids = form.object.send(association).reject(&:persisted?)
|
178
181
|
records = records.to_a.concat(invalids) if invalids.any?
|
179
|
-
end
|
180
|
-
|
182
|
+
end
|
183
|
+
|
181
184
|
content_tag(:div, options[:wrapper_html]) do
|
182
185
|
form.fields_for(association, records) do |f|
|
183
186
|
content_tag(:div, build_attributes(fields_default, basic_fields_markup(options[:fields_html], association))) do
|
@@ -189,24 +192,24 @@ module Abyme
|
|
189
192
|
|
190
193
|
# ADD & REMOVE ASSOCIATION
|
191
194
|
|
192
|
-
# these helpers will call the #create_button method
|
195
|
+
# these helpers will call the #create_button method
|
193
196
|
# to generate the buttons for add and remove associations
|
194
197
|
# with the right action and a default content text for each button
|
195
|
-
|
198
|
+
|
196
199
|
def add_associated_record(options = {}, &block)
|
197
|
-
action =
|
198
|
-
options[:content] ||=
|
200
|
+
action = "click->abyme#add_association"
|
201
|
+
options[:content] ||= "Add Association"
|
199
202
|
create_button(action, options, &block)
|
200
203
|
end
|
201
|
-
|
204
|
+
|
202
205
|
def remove_associated_record(options = {}, &block)
|
203
|
-
action =
|
204
|
-
options[:content] ||=
|
206
|
+
action = "click->abyme#remove_association"
|
207
|
+
options[:content] ||= "Remove Association"
|
205
208
|
create_button(action, options, &block)
|
206
209
|
end
|
207
210
|
|
208
|
-
|
209
|
-
|
211
|
+
alias_method :add_association, :add_associated_record
|
212
|
+
alias_method :remove_association, :remove_associated_record
|
210
213
|
|
211
214
|
private
|
212
215
|
|
@@ -225,17 +228,17 @@ module Abyme
|
|
225
228
|
|
226
229
|
# - html (Hash)
|
227
230
|
# to pass any html attributes you want.
|
228
|
-
|
231
|
+
|
229
232
|
def create_button(action, options, &block)
|
230
233
|
options[:html] ||= {}
|
231
234
|
options[:tag] ||= :button
|
232
|
-
|
233
|
-
if
|
234
|
-
content_tag(options[:tag], {
|
235
|
+
|
236
|
+
if block
|
237
|
+
content_tag(options[:tag], {data: {action: action}}.merge(options[:html])) do
|
235
238
|
capture(&block)
|
236
239
|
end
|
237
240
|
else
|
238
|
-
content_tag(options[:tag], options[:content], {
|
241
|
+
content_tag(options[:tag], options[:content], {data: {action: action}}.merge(options[:html]))
|
239
242
|
end
|
240
243
|
end
|
241
244
|
|
@@ -246,7 +249,7 @@ module Abyme
|
|
246
249
|
|
247
250
|
def basic_fields_markup(html, association = nil)
|
248
251
|
if html && html[:class]
|
249
|
-
html[:class] = "abyme--fields #{association.to_s.singularize}-fields #{html[:class]}"
|
252
|
+
html[:class] = "abyme--fields #{association.to_s.singularize}-fields #{html[:class]}"
|
250
253
|
else
|
251
254
|
html ||= {}
|
252
255
|
html[:class] = "abyme--fields #{association.to_s.singularize}-fields"
|
@@ -274,13 +277,12 @@ module Abyme
|
|
274
277
|
|
275
278
|
# RENDER PARTIAL
|
276
279
|
|
277
|
-
# renders a partial based on the passed path, or will expect a partial to be found in the views/abyme directory.
|
280
|
+
# renders a partial based on the passed path, or will expect a partial to be found in the views/abyme directory.
|
278
281
|
|
279
282
|
def render_association_partial(association, form, partial = nil, context = nil)
|
280
|
-
partial_path = partial ||"abyme/#{association.to_s.singularize}_fields"
|
283
|
+
partial_path = partial || "abyme/#{association.to_s.singularize}_fields"
|
281
284
|
context ||= self
|
282
285
|
context.render(partial: partial_path, locals: {f: form})
|
283
286
|
end
|
284
|
-
|
285
287
|
end
|
286
|
-
end
|
288
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Description:
|
2
|
+
Injects the call to the `abyme_attributes` in the strong params definition of the targeted controller.
|
3
|
+
Also works with namespaced controllers.
|
4
|
+
|
5
|
+
Example:
|
6
|
+
Before :
|
7
|
+
def project_params
|
8
|
+
params.require(:project).permit(:title, :description)
|
9
|
+
end
|
10
|
+
|
11
|
+
rails generate abyme:controller Projects
|
12
|
+
|
13
|
+
After:
|
14
|
+
def project_params
|
15
|
+
params.require(:project).permit(abyme_attributes, :title, :description)
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Abyme
|
4
|
+
module Generators
|
5
|
+
class ControllerGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
def insert_abyme_attributes_in_strong_params
|
9
|
+
return unless File.exists? controller_file_path
|
10
|
+
|
11
|
+
insert_into_file(
|
12
|
+
controller_file_path,
|
13
|
+
"abyme_attributes, ",
|
14
|
+
after: /^(\w|\s)*params\s*(.*)permit\(\s*/
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def controller_file_path
|
21
|
+
Rails.root.join('app', 'controllers', "#{name.downcase.pluralize}_controller.rb")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Description:
|
2
|
+
Generates configuration for the model part :
|
3
|
+
✅ Adds the `includes Abyme::Model` at the top
|
4
|
+
✅ Will add the call to `abymize` below the targeted association, including the optional permitted attributes
|
5
|
+
|
6
|
+
💡 Works with namespaced models
|
7
|
+
|
8
|
+
Example:
|
9
|
+
rails generate abyme:model project tasks description title
|
10
|
+
rails generate abyme:model project participants all
|
11
|
+
|
12
|
+
In project.rb, you will find :
|
13
|
+
class Project < ApplicationRecord
|
14
|
+
include Abyme::Model
|
15
|
+
|
16
|
+
has_many :tasks
|
17
|
+
abymize :tasks, permit: [:description, :title]
|
18
|
+
|
19
|
+
has_many :participants
|
20
|
+
abymize :participants, permit: :all_attributes
|
21
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Abyme
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
argument :association, type: :string, required: true, banner: "association association"
|
9
|
+
argument :attributes, type: :array, default: [], banner: "field field"
|
10
|
+
|
11
|
+
def insert_abyme_config_in_model
|
12
|
+
insert_abyme_configuration unless model_configured?
|
13
|
+
insert_abymized_association
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def insert_abymized_association
|
19
|
+
insert_into_file(model_file_path, after: /(^\s*(has_many|has_one|belongs_to)\s*:#{Regexp.quote(association)}.*$)/ ) do
|
20
|
+
"\n#{insert_indentation}abymize :#{association}#{inject_abyme_attributes}\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def insert_abyme_configuration
|
25
|
+
if namespaced_model
|
26
|
+
model = namespaced_model[2]
|
27
|
+
namespace = namespaced_model[1]
|
28
|
+
insert_into_file(model_file_path, after: /(^\s*class.*#{Regexp.quote(model)}.*$)/) do
|
29
|
+
"\n include Abyme::Model\n"
|
30
|
+
end
|
31
|
+
else
|
32
|
+
inject_into_class(model_file_path, class_name, " include Abyme::Model\n\n")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def assign_names!(name)
|
37
|
+
# Remove abyme namespace
|
38
|
+
name.gsub!(/abyme_/, "")
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def namespaced_model
|
43
|
+
class_name.match(/(.*)[\/::](.*)/)
|
44
|
+
end
|
45
|
+
|
46
|
+
def model_file_path
|
47
|
+
Rails.root.join('app', 'models', "#{name}.rb")
|
48
|
+
end
|
49
|
+
|
50
|
+
def inject_abyme_attributes
|
51
|
+
return '' if attributes.empty?
|
52
|
+
return ", permit: :all_attributes" if attributes.map(&:name).include?('all_attributes')
|
53
|
+
|
54
|
+
", permit: [#{symbolized_attributes.join(', ')}]"
|
55
|
+
end
|
56
|
+
|
57
|
+
def symbolized_attributes
|
58
|
+
attributes.map {|attr| ":#{attr.name.downcase}" }
|
59
|
+
end
|
60
|
+
|
61
|
+
def model_configured?
|
62
|
+
File.read(model_file_path).match?(/Abyme::Model/)
|
63
|
+
end
|
64
|
+
|
65
|
+
def insert_indentation
|
66
|
+
namespaced_model ? " " : " "
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Description:
|
2
|
+
Generates configuration for the model and controller, as well as views templates (see each individual usage pages)
|
3
|
+
|
4
|
+
Example:
|
5
|
+
# Generate files and configuration, not handling attributes
|
6
|
+
rails generate abyme:model project tasks
|
7
|
+
# Generate files and configuration, permitting specified attributes
|
8
|
+
rails generate abyme:model project tasks description title
|
9
|
+
# Generate files and configuration, permitting all attributes
|
10
|
+
rails generate abyme:model project tasks all_attributes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Abyme
|
4
|
+
module Generators
|
5
|
+
class ResourceGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
argument :association, type: :string, required: true, banner: "association association"
|
9
|
+
argument :attributes, type: :array, default: [], banner: "field field"
|
10
|
+
|
11
|
+
def call_generators
|
12
|
+
Rails::Generators.invoke "abyme:model", [name, association, *attributes.map(&:name)]
|
13
|
+
Rails::Generators.invoke "abyme:controller", [name]
|
14
|
+
Rails::Generators.invoke "abyme:view", [association, *attributes.map(&:name)]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Abyme
|
4
|
+
module Generators
|
5
|
+
class StimulusGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
def add_to_stimulus
|
9
|
+
insert_into_file(stimulus_file_path, "\nimport { AbymeController } from 'abyme';\n")
|
10
|
+
insert_into_file(stimulus_file_path, "application.register('abyme', AbymeController);")
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def stimulus_file_path
|
16
|
+
Rails.root.join('app', 'javascript', 'controllers', 'index.js')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|