effective_bootstrap 0.9.5 → 0.9.10
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 +44 -2
- data/app/assets/config/effective_bootstrap_manifest.js +1 -0
- data/app/assets/javascripts/effective_bootstrap.js +1 -0
- data/app/assets/javascripts/effective_editor/input.js +1 -0
- data/app/assets/javascripts/effective_editor/magic-url.js +3 -0
- data/app/assets/javascripts/effective_has_many/initialize.js.coffee +74 -0
- data/app/assets/javascripts/effective_has_many/input.js +2 -0
- data/app/assets/javascripts/effective_has_many/jquery.sortable.js +696 -0
- data/app/assets/stylesheets/effective_bootstrap.scss +1 -0
- data/app/assets/stylesheets/effective_has_many/input.scss +42 -0
- data/app/helpers/effective_form_builder_helper.rb +12 -1
- data/app/models/effective/form_builder.rb +14 -0
- data/app/models/effective/form_inputs/editor.rb +10 -5
- data/app/models/effective/form_inputs/file_field.rb +12 -2
- data/app/models/effective/form_inputs/has_many.rb +175 -0
- data/lib/effective_bootstrap/engine.rb +1 -1
- data/lib/effective_bootstrap/version.rb +1 -1
- metadata +10 -3
@@ -0,0 +1,42 @@
|
|
1
|
+
body.dragging,
|
2
|
+
body.dragging * {
|
3
|
+
cursor: move !important;
|
4
|
+
}
|
5
|
+
|
6
|
+
.form-has-many {
|
7
|
+
.has-many-placeholder {
|
8
|
+
position: relative;
|
9
|
+
height: 2rem;
|
10
|
+
|
11
|
+
&:before {
|
12
|
+
position: absolute;
|
13
|
+
content: '';
|
14
|
+
background-image: asset-data-url('icons/arrow-right-circle.svg');
|
15
|
+
background-repeat: no-repeat;
|
16
|
+
height: 2rem;
|
17
|
+
width: 2rem;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
.has-many-fields.dragged {
|
22
|
+
position: absolute;
|
23
|
+
opacity: 0;
|
24
|
+
z-index: 2000;
|
25
|
+
.has-many-move { display: none; }
|
26
|
+
}
|
27
|
+
|
28
|
+
.has-many-move svg { margin-top: 6px; }
|
29
|
+
.has-many-move { display: none; }
|
30
|
+
|
31
|
+
.has-many-remove { margin-top: 1.5rem; }
|
32
|
+
.has-many-move { margin-top: 1.5rem; }
|
33
|
+
}
|
34
|
+
|
35
|
+
.form-has-many.reordering {
|
36
|
+
.has-many-move { display: inline-block; }
|
37
|
+
}
|
38
|
+
|
39
|
+
.form-has-many.tight {
|
40
|
+
.has-many-remove { margin-top: 0; }
|
41
|
+
.has-many-move { margin-top: 0; }
|
42
|
+
}
|
@@ -2,7 +2,7 @@ module EffectiveFormBuilderHelper
|
|
2
2
|
def effective_form_with(**options, &block)
|
3
3
|
# Compute the default ID
|
4
4
|
subject = Array(options[:scope] || options[:model]).last
|
5
|
-
class_name = subject.class.name.underscore
|
5
|
+
class_name = subject.class.name.parameterize.underscore
|
6
6
|
unique_id = options.except(:model).hash.abs
|
7
7
|
|
8
8
|
html_id = if subject.kind_of?(Symbol)
|
@@ -56,6 +56,17 @@ module EffectiveFormBuilderHelper
|
|
56
56
|
# Assign default ID
|
57
57
|
options[:id] ||= (options[:html].delete(:id) || html_id) unless options.key?(:id)
|
58
58
|
|
59
|
+
# Assign url if engine present
|
60
|
+
options[:url] ||= if options[:engine] && options[:model].present?
|
61
|
+
resource = Effective::Resource.new(options[:model])
|
62
|
+
|
63
|
+
if subject.respond_to?(:persisted?) && subject.persisted?
|
64
|
+
resource.action_path(:update, subject)
|
65
|
+
elsif subject.respond_to?(:new_record?) && subject.new_record?
|
66
|
+
resource.action_path(:create)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
59
70
|
without_error_proc do
|
60
71
|
form_with(**options.merge(builder: Effective::FormBuilder), &block)
|
61
72
|
end
|
@@ -203,5 +203,19 @@ module Effective
|
|
203
203
|
Effective::FormLogics::ShowIfAny.new(*args, builder: self).to_html(&block)
|
204
204
|
end
|
205
205
|
|
206
|
+
# Has Many
|
207
|
+
def has_many(name, collection = nil, options = {}, &block)
|
208
|
+
association = object.class.reflect_on_all_associations.find { |a| a.name == name }
|
209
|
+
raise("expected #{object.class.name} to has_many :#{name}") if association.blank?
|
210
|
+
|
211
|
+
nested_attributes_options = (object.class.nested_attributes_options || {})[name]
|
212
|
+
raise("expected #{object.class.name} to accepts_nested_attributes_for :#{name}") if nested_attributes_options.blank?
|
213
|
+
|
214
|
+
options = collection if collection.kind_of?(Hash)
|
215
|
+
options.merge!(collection: collection) if collection && !collection.kind_of?(Hash)
|
216
|
+
|
217
|
+
Effective::FormInputs::HasMany.new(name, options, builder: self).to_html(&block)
|
218
|
+
end
|
219
|
+
|
206
220
|
end
|
207
221
|
end
|
@@ -15,11 +15,12 @@ module Effective
|
|
15
15
|
|
16
16
|
def input_js_options
|
17
17
|
{
|
18
|
-
modules: {
|
19
|
-
toolbar: toolbar,
|
20
|
-
imageResize: imageResize,
|
18
|
+
modules: {
|
19
|
+
toolbar: toolbar,
|
20
|
+
imageResize: imageResize,
|
21
21
|
imageDropAndPaste: imageDropAndPaste,
|
22
|
-
|
22
|
+
magicUrl: magicUrl,
|
23
|
+
syntax: (content_mode == :code)
|
23
24
|
},
|
24
25
|
theme: 'snow',
|
25
26
|
placeholder: "Add #{name.to_s.pluralize}...",
|
@@ -42,7 +43,7 @@ module Effective
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def imageDropAndPaste
|
45
|
-
active_storage && !(content_mode == :code)
|
46
|
+
active_storage && !(content_mode == :code)
|
46
47
|
end
|
47
48
|
|
48
49
|
def imageResize
|
@@ -57,6 +58,10 @@ module Effective
|
|
57
58
|
}
|
58
59
|
end
|
59
60
|
|
61
|
+
def magicUrl
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
60
65
|
def active_storage
|
61
66
|
return @active_storage unless @active_storage.nil?
|
62
67
|
|
@@ -5,9 +5,9 @@ module Effective
|
|
5
5
|
def build_input(&block)
|
6
6
|
case attachments_style
|
7
7
|
when :card
|
8
|
-
build_attachments + build_uploads + super
|
8
|
+
build_existing_attachments + build_attachments + build_uploads + super
|
9
9
|
when :table, :ck_assets
|
10
|
-
super + build_uploads + build_attachments
|
10
|
+
super + build_existing_attachments + build_uploads + build_attachments
|
11
11
|
else
|
12
12
|
raise('unsupported attachments_style, try :card or :table')
|
13
13
|
end
|
@@ -32,6 +32,16 @@ module Effective
|
|
32
32
|
super(obj, name) && Array(object.public_send(name)).length == 0
|
33
33
|
end
|
34
34
|
|
35
|
+
def build_existing_attachments
|
36
|
+
return ''.html_safe unless multiple?
|
37
|
+
|
38
|
+
attachments = object.send(name)
|
39
|
+
|
40
|
+
attachments.map.with_index do |attachment, index|
|
41
|
+
@builder.hidden_field(name, multiple: true, id: (tag_id + "_#{index}"), value: attachment.signed_id)
|
42
|
+
end.join.html_safe
|
43
|
+
end
|
44
|
+
|
35
45
|
def build_attachments
|
36
46
|
return ''.html_safe unless object.respond_to?(name) && object.send(name).respond_to?(:attached?) && object.send(name).attached?
|
37
47
|
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module Effective
|
2
|
+
module FormInputs
|
3
|
+
class HasMany < Effective::FormInput
|
4
|
+
BLANK = ''.html_safe
|
5
|
+
|
6
|
+
def to_html(&block)
|
7
|
+
content_tag(:div, options[:input]) do
|
8
|
+
has_many_fields_for(block) + has_many_links_for(block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def input_html_options
|
13
|
+
{ class: 'form-has-many mb-4' }
|
14
|
+
end
|
15
|
+
|
16
|
+
def input_js_options
|
17
|
+
{ sortable: true }
|
18
|
+
end
|
19
|
+
|
20
|
+
def collection
|
21
|
+
Array(options[:input][:collection] || object.send(name))
|
22
|
+
end
|
23
|
+
|
24
|
+
# cards: true
|
25
|
+
def display
|
26
|
+
@display ||= (options[:input].delete(:cards) ? :cards : :rows)
|
27
|
+
end
|
28
|
+
|
29
|
+
# add: false
|
30
|
+
def add?
|
31
|
+
return @add unless @add.nil?
|
32
|
+
|
33
|
+
@add ||= begin
|
34
|
+
add = options[:input].delete(:add)
|
35
|
+
add.nil? ? true : add
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# remove: false
|
40
|
+
def remove?
|
41
|
+
return @remove unless @remove.nil?
|
42
|
+
|
43
|
+
@remove ||= begin
|
44
|
+
remove = options[:input].delete(:remove)
|
45
|
+
|
46
|
+
if remove != nil
|
47
|
+
remove
|
48
|
+
else
|
49
|
+
opts = (object.class.nested_attributes_options[name] || {})
|
50
|
+
opts[:update_only] != true && opts[:allow_destroy] != false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# reorder: true
|
56
|
+
def reorder?
|
57
|
+
return @reorder unless @reorder.nil?
|
58
|
+
|
59
|
+
@reorder ||= begin
|
60
|
+
reorder = options[:input].delete(:reorder)
|
61
|
+
|
62
|
+
if reorder != nil
|
63
|
+
reorder
|
64
|
+
else
|
65
|
+
build_resource().class.columns_hash['position']&.type == :integer
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def has_many_fields_for(block)
|
73
|
+
collection.map { |resource| render_resource(resource, block) }.join.html_safe
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_many_links_for(block)
|
77
|
+
return BLANK unless add? || reorder?
|
78
|
+
|
79
|
+
content_tag(:div, class: 'has-many-links text-center mt-2') do
|
80
|
+
[(link_to_add(block) if add?), (link_to_reorder(block) if reorder?)].compact.join(' ').html_safe
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def render_resource(resource, block)
|
85
|
+
remove = BLANK
|
86
|
+
|
87
|
+
content = @builder.fields_for(name, resource) do |form|
|
88
|
+
fields = block.call(form)
|
89
|
+
|
90
|
+
remove += form.super_hidden_field(:_destroy) if remove? && resource.persisted?
|
91
|
+
remove += form.super_hidden_field(:position) if reorder? && !fields.include?('][position]')
|
92
|
+
|
93
|
+
fields
|
94
|
+
end
|
95
|
+
|
96
|
+
remove += link_to_remove(resource) if remove?
|
97
|
+
|
98
|
+
content_tag(:div, render_fields(content, remove), class: 'has-many-fields')
|
99
|
+
end
|
100
|
+
|
101
|
+
def render_fields(content, remove)
|
102
|
+
case display
|
103
|
+
when :rows
|
104
|
+
content_tag(:div, class: 'form-row') do
|
105
|
+
(reorder? ? content_tag(:div, has_many_move, class: 'col-auto') : BLANK) +
|
106
|
+
content_tag(:div, content, class: 'col mr-auto') +
|
107
|
+
content_tag(:div, remove, class: 'col-auto')
|
108
|
+
end
|
109
|
+
when :cards
|
110
|
+
raise('unsupported')
|
111
|
+
else
|
112
|
+
content + remove
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def render_template(block)
|
117
|
+
resource = build_resource()
|
118
|
+
index = object.send(name).index(resource)
|
119
|
+
|
120
|
+
html = render_resource(resource, block)
|
121
|
+
html.gsub!("#{name}_attributes][#{index}]", "#{name}_attributes][HASMANYINDEX]")
|
122
|
+
html.gsub!("#{name}_attributes_#{index}_", "#{name}_attributes_HASMANYINDEX_")
|
123
|
+
|
124
|
+
html.html_safe
|
125
|
+
end
|
126
|
+
|
127
|
+
def link_to_add(block)
|
128
|
+
content_tag(
|
129
|
+
:button,
|
130
|
+
icon('plus-circle') + 'Add Another',
|
131
|
+
class: 'has-many-add btn btn-secondary',
|
132
|
+
title: 'Add Another',
|
133
|
+
data: {
|
134
|
+
'effective-form-has-many-add': true,
|
135
|
+
'effective-form-has-many-template': render_template(block)
|
136
|
+
}
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
def link_to_reorder(block)
|
141
|
+
content_tag(
|
142
|
+
:button,
|
143
|
+
icon('list') + 'Reorder',
|
144
|
+
class: 'has-many-reorder btn btn-secondary',
|
145
|
+
title: 'Reorder',
|
146
|
+
data: {
|
147
|
+
'effective-form-has-many-reorder': true,
|
148
|
+
}
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
def link_to_remove(resource)
|
153
|
+
content_tag(
|
154
|
+
:button,
|
155
|
+
icon('trash-2') + 'Remove',
|
156
|
+
class: 'has-many-remove btn btn-danger',
|
157
|
+
title: 'Remove',
|
158
|
+
data: {
|
159
|
+
'confirm': "Remove #{resource}?",
|
160
|
+
'effective-form-has-many-remove': true,
|
161
|
+
}
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
def has_many_move
|
166
|
+
@has_many_move ||= content_tag(:span, icon('move'), class: 'has-many-move')
|
167
|
+
end
|
168
|
+
|
169
|
+
def build_resource
|
170
|
+
@build_resource ||= object.send(name).build().tap { |resource| object.send(name).delete(resource) }
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_bootstrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -103,6 +103,7 @@ extra_rdoc_files: []
|
|
103
103
|
files:
|
104
104
|
- MIT-LICENSE
|
105
105
|
- README.md
|
106
|
+
- app/assets/config/effective_bootstrap_manifest.js
|
106
107
|
- app/assets/images/icons/activity.svg
|
107
108
|
- app/assets/images/icons/airplay.svg
|
108
109
|
- app/assets/images/icons/alert-circle.svg
|
@@ -414,9 +415,13 @@ files:
|
|
414
415
|
- app/assets/javascripts/effective_editor/image-resize.js
|
415
416
|
- app/assets/javascripts/effective_editor/initialize.js.coffee
|
416
417
|
- app/assets/javascripts/effective_editor/input.js
|
418
|
+
- app/assets/javascripts/effective_editor/magic-url.js
|
417
419
|
- app/assets/javascripts/effective_editor/quill.js
|
418
420
|
- app/assets/javascripts/effective_file/initialize.js.coffee
|
419
421
|
- app/assets/javascripts/effective_file/input.js
|
422
|
+
- app/assets/javascripts/effective_has_many/initialize.js.coffee
|
423
|
+
- app/assets/javascripts/effective_has_many/input.js
|
424
|
+
- app/assets/javascripts/effective_has_many/jquery.sortable.js
|
420
425
|
- app/assets/javascripts/effective_integer/initialize.js.coffee
|
421
426
|
- app/assets/javascripts/effective_integer/input.js
|
422
427
|
- app/assets/javascripts/effective_number_text/initialize.js.coffee
|
@@ -582,6 +587,7 @@ files:
|
|
582
587
|
- app/assets/stylesheets/effective_editor/overrides.scss
|
583
588
|
- app/assets/stylesheets/effective_editor/quill.scss
|
584
589
|
- app/assets/stylesheets/effective_file/input.scss
|
590
|
+
- app/assets/stylesheets/effective_has_many/input.scss
|
585
591
|
- app/assets/stylesheets/effective_radio/input.scss
|
586
592
|
- app/assets/stylesheets/effective_rich_text_area/input.scss
|
587
593
|
- app/assets/stylesheets/effective_select/bootstrap-theme.css
|
@@ -611,6 +617,7 @@ files:
|
|
611
617
|
- app/models/effective/form_inputs/file_field.rb
|
612
618
|
- app/models/effective/form_inputs/float_field.rb
|
613
619
|
- app/models/effective/form_inputs/form_group.rb
|
620
|
+
- app/models/effective/form_inputs/has_many.rb
|
614
621
|
- app/models/effective/form_inputs/hidden_field.rb
|
615
622
|
- app/models/effective/form_inputs/integer_field.rb
|
616
623
|
- app/models/effective/form_inputs/number_field.rb
|
@@ -666,7 +673,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
666
673
|
- !ruby/object:Gem::Version
|
667
674
|
version: '0'
|
668
675
|
requirements: []
|
669
|
-
rubygems_version: 3.1.
|
676
|
+
rubygems_version: 3.1.2
|
670
677
|
signing_key:
|
671
678
|
specification_version: 4
|
672
679
|
summary: Everything you need to get set up with bootstrap 4.
|