effective_bootstrap 0.9.6 → 0.9.11
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 +50 -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 +77 -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_checks/input.scss +1 -1
- 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/checks.rb +19 -8
- data/app/models/effective/form_inputs/editor.rb +10 -5
- data/app/models/effective/form_inputs/has_many.rb +207 -0
- data/lib/effective_bootstrap/engine.rb +1 -1
- data/lib/effective_bootstrap/version.rb +1 -1
- metadata +24 -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
|
@@ -50,18 +50,29 @@ module Effective
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def build_label
|
53
|
-
return BLANK if options[:label] == false
|
53
|
+
return BLANK if options[:label] == false && !actions?
|
54
54
|
return BLANK if name.kind_of?(NilClass)
|
55
55
|
|
56
|
-
text =
|
56
|
+
text = begin
|
57
|
+
if options[:label] == false
|
58
|
+
nil
|
59
|
+
elsif options[:label].key?(:text)
|
60
|
+
options[:label].delete(:text)
|
61
|
+
elsif object.present?
|
62
|
+
object.class.human_attribute_name(name)
|
63
|
+
end || BLANK
|
64
|
+
end.html_safe
|
65
|
+
|
66
|
+
actions = if !disabled? && actions?
|
67
|
+
content_tag(:div, class: 'effective-checks-actions text-muted') do
|
68
|
+
link_to('Select All', '#', 'data-effective-checks-all': true) + ' - ' + link_to('Select None', '#', 'data-effective-checks-none': true)
|
69
|
+
end
|
70
|
+
end
|
57
71
|
|
58
72
|
content_tag(:label, options[:label]) do
|
59
|
-
text
|
60
|
-
unless disabled? || !actions?
|
61
|
-
link_to('Select All', '#', 'data-effective-checks-all': true) + ' - ' + link_to('Select None', '#', 'data-effective-checks-none': true)
|
62
|
-
end
|
63
|
-
end
|
73
|
+
[text, actions].compact.join.html_safe
|
64
74
|
end
|
75
|
+
|
65
76
|
end
|
66
77
|
|
67
78
|
def build_item(builder)
|
@@ -91,7 +102,7 @@ module Effective
|
|
91
102
|
|
92
103
|
def actions? # default true
|
93
104
|
return @actions unless @actions.nil?
|
94
|
-
@actions = (options.delete(:actions) != false)
|
105
|
+
@actions = (options[:input].delete(:actions) != false)
|
95
106
|
end
|
96
107
|
|
97
108
|
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
|
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module Effective
|
2
|
+
module FormInputs
|
3
|
+
class HasMany < Effective::FormInput
|
4
|
+
BLANK = ''.html_safe
|
5
|
+
|
6
|
+
def to_html(&block)
|
7
|
+
object.send(name).build() if build? && collection.blank?
|
8
|
+
|
9
|
+
errors = (@builder.error(name) if errors?) || BLANK
|
10
|
+
|
11
|
+
errors + content_tag(:div, options[:input]) do
|
12
|
+
has_many_fields_for(block) + has_many_links_for(block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def input_html_options
|
17
|
+
{ class: 'form-has-many mb-4' }
|
18
|
+
end
|
19
|
+
|
20
|
+
def input_js_options
|
21
|
+
{ sortable: true }
|
22
|
+
end
|
23
|
+
|
24
|
+
def collection
|
25
|
+
Array(options[:input][:collection] || object.send(name))
|
26
|
+
end
|
27
|
+
|
28
|
+
# cards: false
|
29
|
+
def display
|
30
|
+
@display ||= (options[:input].delete(:cards) ? :cards : :rows)
|
31
|
+
end
|
32
|
+
|
33
|
+
# build: true
|
34
|
+
def build?
|
35
|
+
return @build unless @build.nil?
|
36
|
+
|
37
|
+
@build ||= begin
|
38
|
+
build = options[:input].delete(:build)
|
39
|
+
build.nil? ? true : build
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# add: true
|
44
|
+
def add?
|
45
|
+
return @add unless @add.nil?
|
46
|
+
|
47
|
+
@add ||= begin
|
48
|
+
add = options[:input].delete(:add)
|
49
|
+
add.nil? ? true : add
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# errors: true
|
54
|
+
def errors?
|
55
|
+
return @errors unless @errors.nil?
|
56
|
+
|
57
|
+
@errors ||= begin
|
58
|
+
errors = options[:input].delete(:errors)
|
59
|
+
errors.nil? ? true : errors
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# remove: true
|
64
|
+
def remove?
|
65
|
+
return @remove unless @remove.nil?
|
66
|
+
|
67
|
+
@remove ||= begin
|
68
|
+
remove = options[:input].delete(:remove)
|
69
|
+
|
70
|
+
if remove != nil
|
71
|
+
remove
|
72
|
+
else
|
73
|
+
opts = (object.class.nested_attributes_options[name] || {})
|
74
|
+
opts[:update_only] != true && opts[:allow_destroy] != false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# reorder: true
|
80
|
+
def reorder?
|
81
|
+
return @reorder unless @reorder.nil?
|
82
|
+
|
83
|
+
@reorder ||= begin
|
84
|
+
reorder = options[:input].delete(:reorder)
|
85
|
+
|
86
|
+
if reorder != nil
|
87
|
+
reorder
|
88
|
+
else
|
89
|
+
build_resource().class.columns_hash['position']&.type == :integer
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def has_many_fields_for(block)
|
97
|
+
collection.map { |resource| render_resource(resource, block) }.join.html_safe
|
98
|
+
end
|
99
|
+
|
100
|
+
def has_many_links_for(block)
|
101
|
+
return BLANK unless add? || reorder?
|
102
|
+
|
103
|
+
content_tag(:div, class: 'has-many-links text-center mt-2') do
|
104
|
+
[*(link_to_add(block) if add?), *(link_to_reorder(block) if reorder?)].join(' ').html_safe
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def render_resource(resource, block)
|
109
|
+
remove = BLANK
|
110
|
+
|
111
|
+
content = @builder.fields_for(name, resource) do |form|
|
112
|
+
fields = block.call(form)
|
113
|
+
|
114
|
+
remove += form.super_hidden_field(:_destroy) if remove? && resource.persisted?
|
115
|
+
remove += form.super_hidden_field(:position) if reorder? && !fields.include?('][position]')
|
116
|
+
|
117
|
+
fields
|
118
|
+
end
|
119
|
+
|
120
|
+
remove += link_to_remove(resource) if remove?
|
121
|
+
|
122
|
+
content_tag(:div, render_fields(content, remove), class: 'has-many-fields')
|
123
|
+
end
|
124
|
+
|
125
|
+
def render_fields(content, remove)
|
126
|
+
case display
|
127
|
+
when :rows
|
128
|
+
content_tag(:div, class: 'form-row') do
|
129
|
+
(reorder? ? content_tag(:div, has_many_move, class: 'col-auto') : BLANK) +
|
130
|
+
content_tag(:div, content, class: 'col mr-auto') +
|
131
|
+
content_tag(:div, remove, class: 'col-auto')
|
132
|
+
end
|
133
|
+
when :cards
|
134
|
+
raise('unsupported')
|
135
|
+
else
|
136
|
+
content + remove
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def render_template(block)
|
141
|
+
resource = build_resource()
|
142
|
+
index = collection.length
|
143
|
+
|
144
|
+
html = render_resource(resource, block)
|
145
|
+
|
146
|
+
unless html.include?("#{name}_attributes][#{index}]")
|
147
|
+
raise('unexpected index. unable to render resource template.')
|
148
|
+
end
|
149
|
+
|
150
|
+
html.gsub!("#{name}_attributes][#{index}]", "#{name}_attributes][HASMANYINDEX]")
|
151
|
+
html.gsub!("#{name}_attributes_#{index}_", "#{name}_attributes_HASMANYINDEX_")
|
152
|
+
|
153
|
+
html.html_safe
|
154
|
+
end
|
155
|
+
|
156
|
+
def link_to_add(block)
|
157
|
+
content_tag(
|
158
|
+
:button,
|
159
|
+
icon('plus-circle') + 'Add Another',
|
160
|
+
class: 'has-many-add btn btn-secondary',
|
161
|
+
title: 'Add Another',
|
162
|
+
data: {
|
163
|
+
'effective-form-has-many-add': true,
|
164
|
+
'effective-form-has-many-template': render_template(block)
|
165
|
+
}
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
def link_to_reorder(block)
|
170
|
+
content_tag(
|
171
|
+
:button,
|
172
|
+
icon('list') + 'Reorder',
|
173
|
+
class: 'has-many-reorder btn btn-secondary',
|
174
|
+
title: 'Reorder',
|
175
|
+
data: {
|
176
|
+
'effective-form-has-many-reorder': true,
|
177
|
+
}
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
def link_to_remove(resource)
|
182
|
+
content_tag(
|
183
|
+
:button,
|
184
|
+
icon('trash-2') + 'Remove',
|
185
|
+
class: 'has-many-remove btn btn-danger',
|
186
|
+
title: 'Remove',
|
187
|
+
data: {
|
188
|
+
'confirm': "Remove #{resource}?",
|
189
|
+
'effective-form-has-many-remove': true,
|
190
|
+
}
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
def has_many_move
|
195
|
+
@has_many_move ||= content_tag(:span, icon('move'), class: 'has-many-move')
|
196
|
+
end
|
197
|
+
|
198
|
+
def build_resource
|
199
|
+
# Using .new() here seems like it should work but it doesn't. It changes the index
|
200
|
+
@build_resource ||= object.send(name).build().tap do |resource|
|
201
|
+
object.send(name).delete(resource)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
end
|
207
|
+
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.11
|
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-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: haml
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Everything you need to get set up with bootstrap 4.
|
98
112
|
email:
|
99
113
|
- info@codeandeffect.com
|
@@ -103,6 +117,7 @@ extra_rdoc_files: []
|
|
103
117
|
files:
|
104
118
|
- MIT-LICENSE
|
105
119
|
- README.md
|
120
|
+
- app/assets/config/effective_bootstrap_manifest.js
|
106
121
|
- app/assets/images/icons/activity.svg
|
107
122
|
- app/assets/images/icons/airplay.svg
|
108
123
|
- app/assets/images/icons/alert-circle.svg
|
@@ -414,9 +429,13 @@ files:
|
|
414
429
|
- app/assets/javascripts/effective_editor/image-resize.js
|
415
430
|
- app/assets/javascripts/effective_editor/initialize.js.coffee
|
416
431
|
- app/assets/javascripts/effective_editor/input.js
|
432
|
+
- app/assets/javascripts/effective_editor/magic-url.js
|
417
433
|
- app/assets/javascripts/effective_editor/quill.js
|
418
434
|
- app/assets/javascripts/effective_file/initialize.js.coffee
|
419
435
|
- app/assets/javascripts/effective_file/input.js
|
436
|
+
- app/assets/javascripts/effective_has_many/initialize.js.coffee
|
437
|
+
- app/assets/javascripts/effective_has_many/input.js
|
438
|
+
- app/assets/javascripts/effective_has_many/jquery.sortable.js
|
420
439
|
- app/assets/javascripts/effective_integer/initialize.js.coffee
|
421
440
|
- app/assets/javascripts/effective_integer/input.js
|
422
441
|
- app/assets/javascripts/effective_number_text/initialize.js.coffee
|
@@ -582,6 +601,7 @@ files:
|
|
582
601
|
- app/assets/stylesheets/effective_editor/overrides.scss
|
583
602
|
- app/assets/stylesheets/effective_editor/quill.scss
|
584
603
|
- app/assets/stylesheets/effective_file/input.scss
|
604
|
+
- app/assets/stylesheets/effective_has_many/input.scss
|
585
605
|
- app/assets/stylesheets/effective_radio/input.scss
|
586
606
|
- app/assets/stylesheets/effective_rich_text_area/input.scss
|
587
607
|
- app/assets/stylesheets/effective_select/bootstrap-theme.css
|
@@ -611,6 +631,7 @@ files:
|
|
611
631
|
- app/models/effective/form_inputs/file_field.rb
|
612
632
|
- app/models/effective/form_inputs/float_field.rb
|
613
633
|
- app/models/effective/form_inputs/form_group.rb
|
634
|
+
- app/models/effective/form_inputs/has_many.rb
|
614
635
|
- app/models/effective/form_inputs/hidden_field.rb
|
615
636
|
- app/models/effective/form_inputs/integer_field.rb
|
616
637
|
- app/models/effective/form_inputs/number_field.rb
|
@@ -666,7 +687,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
666
687
|
- !ruby/object:Gem::Version
|
667
688
|
version: '0'
|
668
689
|
requirements: []
|
669
|
-
rubygems_version: 3.1.
|
690
|
+
rubygems_version: 3.1.2
|
670
691
|
signing_key:
|
671
692
|
specification_version: 4
|
672
693
|
summary: Everything you need to get set up with bootstrap 4.
|