abyme 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|