effective_bootstrap 0.13.2 → 0.13.3
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 +66 -0
- data/app/helpers/effective_form_builder_helper.rb +3 -0
- data/app/helpers/effective_table_builder_helper.rb +10 -0
- data/app/models/effective/table_builder.rb +195 -0
- data/app/models/effective/table_row.rb +45 -0
- data/app/models/effective/table_rows/boolean.rb +17 -0
- data/app/models/effective/table_rows/collection.rb +14 -0
- data/app/models/effective/table_rows/content_for.rb +15 -0
- data/app/models/effective/table_rows/effective_address.rb +13 -0
- data/app/models/effective/table_rows/email_field.rb +13 -0
- data/app/models/effective/table_rows/file_field.rb +13 -0
- data/app/models/effective/table_rows/percent_field.rb +13 -0
- data/app/models/effective/table_rows/price_field.rb +13 -0
- data/app/models/effective/table_rows/text_area.rb +13 -0
- data/app/models/effective/table_rows/url_field.rb +13 -0
- data/lib/effective_bootstrap/version.rb +1 -1
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cc712dfbfdacf4feb17b2e3dc016f6fdefd3a9fd1935dbdf92425c2b607d99b
|
4
|
+
data.tar.gz: 7cf8df3af6713f5ad519c583374c0e2db10b91ff9eaf14bbebff19b8011da24e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b85f3fa66ddcf566a27dff5a60ab3a71a62827d150c440bfede05163016330e5f4189b29dc195d021fa900826654f94dfd479057879905e0f8b3281879168a1
|
7
|
+
data.tar.gz: 227f0c30431c24fff57d42f70d14540de193939d848b9a89bc951633e0eb7c5ac6a4f828394335a92fbada107021e6bba27453a322ee88d18c2d7af4c00de075
|
data/README.md
CHANGED
@@ -697,8 +697,74 @@ The `f.save` is purely a input submit button.
|
|
697
697
|
= f.save 'Save 2'
|
698
698
|
```
|
699
699
|
|
700
|
+
## Table Builder
|
700
701
|
|
702
|
+
Use `effective_table_with(resource)` to intelligently output a table of attributes for a resource.
|
701
703
|
|
704
|
+
In your view:
|
705
|
+
|
706
|
+
```
|
707
|
+
= effective_table_with(user, only: [:first_name, :last_name])
|
708
|
+
```
|
709
|
+
|
710
|
+
will output the following html:
|
711
|
+
|
712
|
+
```
|
713
|
+
<table class='table table-striped table-hover>
|
714
|
+
<tbody>
|
715
|
+
<tr>
|
716
|
+
<td>First Name</td>
|
717
|
+
<td>Peter</td>
|
718
|
+
</tr>
|
719
|
+
<tr>
|
720
|
+
<td>Last Name</td>
|
721
|
+
<td>Pan</td>
|
722
|
+
</tr>
|
723
|
+
</tbody>
|
724
|
+
</table>
|
725
|
+
```
|
726
|
+
|
727
|
+
You can pass `only:` and `except:` to specify which attributes to display.
|
728
|
+
|
729
|
+
To override the content of just one row:
|
730
|
+
|
731
|
+
```
|
732
|
+
= effective_table_with(user) do |f|
|
733
|
+
= f.content_for :first_name, label: 'Cool First Name' do
|
734
|
+
%strong= f.object.first_name
|
735
|
+
```
|
736
|
+
|
737
|
+
will generate the html:
|
738
|
+
|
739
|
+
`<tr><td>Cool First Name</td><td><strong>Peter</strong></td></tr>`
|
740
|
+
|
741
|
+
### Work with existing forms
|
742
|
+
|
743
|
+
The table builder is intended to display based off your existing forms.
|
744
|
+
|
745
|
+
Any `effective_form_with` or `_fields` partial will work to define the attributes displayed and the order they are displayed.
|
746
|
+
|
747
|
+
A check_box will be rendered as a boolean, text areas use simple_format, f.show_if and f.hide_if logic work.
|
748
|
+
|
749
|
+
If you use `f.text_field :first_name, label: 'Cool First Name'` in your form, it will flow through to the table.
|
750
|
+
|
751
|
+
To render a table based off an existing `effective_form_with`:
|
752
|
+
|
753
|
+
```
|
754
|
+
= effective_table_with(user) do |f|
|
755
|
+
= render('users/form', user: user)
|
756
|
+
```
|
757
|
+
|
758
|
+
or just the fields partial
|
759
|
+
|
760
|
+
```
|
761
|
+
= effective_table_with(user, only: [:first_name, :last_name]) do |f|
|
762
|
+
= render('users/fields_demographics', f: f)
|
763
|
+
```
|
764
|
+
|
765
|
+
You can specify `only:` and `except:` and use `f.content_for` to override a row in all these use cases.
|
766
|
+
|
767
|
+
All values flow through to i18n and can be overriden, same as the form labels, in the locale .yml file.
|
702
768
|
|
703
769
|
## License
|
704
770
|
|
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
module EffectiveFormBuilderHelper
|
4
4
|
def effective_form_with(**options, &block)
|
5
|
+
# This allows us to call effective_form_with inside an effective_table_with and just get the fields
|
6
|
+
return @_effective_table_builder.capture(&block) if @_effective_table_builder
|
7
|
+
|
5
8
|
# Compute the default ID
|
6
9
|
subject = Array(options[:model] || options[:scope]).last
|
7
10
|
class_name = (options[:scope] || subject.class.name.parameterize.underscore)
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class TableBuilder
|
5
|
+
FILTER_PARAMETERS = [:password, :password_confirmation, :created_at, :updated_at]
|
6
|
+
|
7
|
+
attr_accessor :object, :template, :options
|
8
|
+
|
9
|
+
# A Hash of :first_name => "<tr><td>First Name</td><td>Bob</td></tr>"
|
10
|
+
attr_accessor :rows
|
11
|
+
attr_accessor :content_fors
|
12
|
+
|
13
|
+
delegate :content_tag, to: :template
|
14
|
+
|
15
|
+
def initialize(object, template, options = {}, &block)
|
16
|
+
raise('resource must be an ActiveRecord::Base') unless object.is_a?(ActiveRecord::Base)
|
17
|
+
|
18
|
+
@object = object
|
19
|
+
@template = template
|
20
|
+
@options = options
|
21
|
+
|
22
|
+
@rows = {}
|
23
|
+
@content_fors = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def render(&block)
|
27
|
+
# This runs the form partial over this table builder
|
28
|
+
capture(&block) if block_given?
|
29
|
+
|
30
|
+
# Build from the resource if we didn't do anything in the block
|
31
|
+
build_resource_rows if rows.blank?
|
32
|
+
|
33
|
+
only = Array(options[:only])
|
34
|
+
except = Array(options[:except])
|
35
|
+
filtered = filter_parameters
|
36
|
+
|
37
|
+
content = rows.merge(content_fors)
|
38
|
+
content = content.slice(*only) if only.present?
|
39
|
+
content = content.except(*except) if except.present?
|
40
|
+
content = content.except(*filtered) if filtered.present?
|
41
|
+
|
42
|
+
content_tag(:table, class: options.fetch(:class, 'table table-striped table-hover')) do
|
43
|
+
content_tag(:tbody, content.values.join.html_safe)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def capture(&block)
|
48
|
+
begin
|
49
|
+
template.instance_variable_set(:@_effective_table_builder, self)
|
50
|
+
template.capture(self, &block)
|
51
|
+
ensure
|
52
|
+
template.instance_variable_set(:@_effective_table_builder, nil)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_resource_rows
|
57
|
+
Effective::Resource.new(object).klass_attributes(sort: true).each do |name, options|
|
58
|
+
case options.first
|
59
|
+
when :boolean
|
60
|
+
boolean_row(name)
|
61
|
+
when :text
|
62
|
+
text_area(name)
|
63
|
+
when :string
|
64
|
+
(name.to_s.include?('email') && value(name).to_s.include?('@')) ? email_field(name) : text_field(name)
|
65
|
+
else default_row(name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def filter_parameters
|
71
|
+
FILTER_PARAMETERS + Array(object.class.try(:filter_parameters)) + Array(Rails.application.config.filter_parameters)
|
72
|
+
end
|
73
|
+
|
74
|
+
def human_attribute_name(name)
|
75
|
+
if object.respond_to?(:human_attribute_name)
|
76
|
+
object.human_attribute_name(name)
|
77
|
+
else
|
78
|
+
(name.to_s.split('.').last.to_s.titleize || '')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def value(name)
|
83
|
+
object.send(name)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Call default_row for any form field
|
87
|
+
def method_missing(method, *args, **kwargs, &block)
|
88
|
+
default_row(args[0], **kwargs, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Assign the <tr><td>...</td></tr> to the @rows Hash
|
92
|
+
def default_row(name, options = {}, &block)
|
93
|
+
rows[name] = TableRow.new(name, options, builder: self).to_html
|
94
|
+
end
|
95
|
+
|
96
|
+
def boolean_row(name, options = {})
|
97
|
+
rows[name] = TableRows::Boolean.new(name, options, builder: self).to_html
|
98
|
+
end
|
99
|
+
alias_method :check_box, :boolean_row
|
100
|
+
|
101
|
+
def collection_row(name, collection, options = {}, &block)
|
102
|
+
rows[name] = if [true, false].include?(value(name))
|
103
|
+
TableRows::Boolean.new(name, options, builder: self).to_html
|
104
|
+
else
|
105
|
+
TableRows::Collection.new(name, collection, options, builder: self).to_html
|
106
|
+
end
|
107
|
+
end
|
108
|
+
alias_method :select, :collection_row
|
109
|
+
alias_method :checks, :collection_row
|
110
|
+
alias_method :radios, :collection_row
|
111
|
+
|
112
|
+
def email_field(name, options = {})
|
113
|
+
rows[name] = TableRows::EmailField.new(name, options, builder: self).to_html
|
114
|
+
end
|
115
|
+
alias_method :email_cc_field, :email_field
|
116
|
+
|
117
|
+
def file_field(name, options = {})
|
118
|
+
rows[name] = TableRows::FileField.new(name, options, builder: self).to_html
|
119
|
+
end
|
120
|
+
|
121
|
+
def form_group(name = nil, options = {}, &block)
|
122
|
+
# Nothing to do
|
123
|
+
end
|
124
|
+
|
125
|
+
def hidden_field(name = nil, options = {})
|
126
|
+
# Nothing to do
|
127
|
+
end
|
128
|
+
|
129
|
+
def search_field(name, options = {})
|
130
|
+
# Nothing to do
|
131
|
+
end
|
132
|
+
|
133
|
+
def password_field(name, options = {})
|
134
|
+
# Nothing to do
|
135
|
+
end
|
136
|
+
|
137
|
+
def effective_address(name, options = {})
|
138
|
+
rows[name] = TableRows::EffectiveAddress.new(name, options, builder: self).to_html
|
139
|
+
end
|
140
|
+
|
141
|
+
def percent_field(name, options = {})
|
142
|
+
rows[name] = TableRows::PercentField.new(name, options, builder: self).to_html
|
143
|
+
end
|
144
|
+
|
145
|
+
def price_field(name, options = {})
|
146
|
+
rows[name] = TableRows::PriceField.new(name, options, builder: self).to_html
|
147
|
+
end
|
148
|
+
|
149
|
+
def save(name, options = {})
|
150
|
+
# Nothing to do
|
151
|
+
end
|
152
|
+
|
153
|
+
def submit(name, options = {}, &block)
|
154
|
+
# Nothing to do
|
155
|
+
end
|
156
|
+
|
157
|
+
def text_area(name, options = {})
|
158
|
+
rows[name] = TableRows::TextArea.new(name, options, builder: self).to_html
|
159
|
+
end
|
160
|
+
|
161
|
+
def url_field(name, options = {})
|
162
|
+
rows[name] = TableRows::UrlField.new(name, options, builder: self).to_html
|
163
|
+
end
|
164
|
+
|
165
|
+
def content_for(name, options = {}, &block)
|
166
|
+
content_fors[name] = TableRows::ContentFor.new(name, options, builder: self).to_html(&block)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Logics
|
170
|
+
def hide_if(name, selected, &block)
|
171
|
+
template.capture(self, &block) unless value(name) == selected
|
172
|
+
end
|
173
|
+
|
174
|
+
def show_if(name, selected, &block)
|
175
|
+
template.capture(self, &block) if value(name) == selected
|
176
|
+
end
|
177
|
+
|
178
|
+
def show_if_any(name, options, &block)
|
179
|
+
template.capture(self, &block) if Array(options).include?(value(name))
|
180
|
+
end
|
181
|
+
|
182
|
+
# Has Many
|
183
|
+
def has_many(name, collection = nil, options = {}, &block)
|
184
|
+
raise('unsupported')
|
185
|
+
end
|
186
|
+
|
187
|
+
def fields_for(name, object, options = {}, &block)
|
188
|
+
builder = TableBuilder.new(object, template, options.merge(prefix: human_attribute_name(name)))
|
189
|
+
builder.render(&block)
|
190
|
+
builder.rows.each { |child, content| rows["#{name}_#{child}".to_sym] = content }
|
191
|
+
end
|
192
|
+
alias_method :effective_fields_for, :fields_for
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class TableRow
|
5
|
+
attr_accessor :name, :options, :builder, :template
|
6
|
+
|
7
|
+
delegate :object, to: :builder
|
8
|
+
delegate :capture, :content_tag, :image_tag, :link_to, :mail_to, :icon, to: :@template
|
9
|
+
|
10
|
+
# So this takes in the options for an entire form group.
|
11
|
+
def initialize(name, options, builder:)
|
12
|
+
@builder = builder
|
13
|
+
@template = builder.template
|
14
|
+
|
15
|
+
@name = name
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
# Intended for override
|
20
|
+
def content
|
21
|
+
value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Render method
|
25
|
+
def to_html(&block)
|
26
|
+
content_tag(:tr) do
|
27
|
+
content_tag(:td, label) + content_tag(:td, content.presence || '-')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Humanized label or the label from form
|
32
|
+
def label
|
33
|
+
text = options[:label] || builder.human_attribute_name(name)
|
34
|
+
prefix = builder.options[:prefix]
|
35
|
+
|
36
|
+
[*prefix, text].join(': ')
|
37
|
+
end
|
38
|
+
|
39
|
+
# Value from resource
|
40
|
+
def value
|
41
|
+
options[:value] || builder.value(name)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
module TableRows
|
5
|
+
class Boolean < Effective::TableRow
|
6
|
+
|
7
|
+
def content
|
8
|
+
if value
|
9
|
+
template.badge('YES')
|
10
|
+
else
|
11
|
+
template.badge('NO', class: 'badge badge-light')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
module TableRows
|
5
|
+
class Collection < Effective::TableRow
|
6
|
+
|
7
|
+
def initialize(name, collection, options, builder:)
|
8
|
+
@collection = collection
|
9
|
+
super(name, options, builder: builder)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
module TableRows
|
5
|
+
class ContentFor < Effective::TableRow
|
6
|
+
|
7
|
+
def to_html(&block)
|
8
|
+
content_tag(:tr) do
|
9
|
+
content_tag(:td, label) + content_tag(:td, template.capture(&block))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
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.13.
|
4
|
+
version: 0.13.3
|
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: 2023-04-
|
11
|
+
date: 2023-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -647,6 +647,7 @@ files:
|
|
647
647
|
- app/helpers/effective_editor_helper.rb
|
648
648
|
- app/helpers/effective_form_builder_helper.rb
|
649
649
|
- app/helpers/effective_icons_helper.rb
|
650
|
+
- app/helpers/effective_table_builder_helper.rb
|
650
651
|
- app/models/effective/form_builder.rb
|
651
652
|
- app/models/effective/form_input.rb
|
652
653
|
- app/models/effective/form_inputs/article_editor.rb
|
@@ -693,6 +694,18 @@ files:
|
|
693
694
|
- app/models/effective/form_logics/hide_if.rb
|
694
695
|
- app/models/effective/form_logics/show_if.rb
|
695
696
|
- app/models/effective/form_logics/show_if_any.rb
|
697
|
+
- app/models/effective/table_builder.rb
|
698
|
+
- app/models/effective/table_row.rb
|
699
|
+
- app/models/effective/table_rows/boolean.rb
|
700
|
+
- app/models/effective/table_rows/collection.rb
|
701
|
+
- app/models/effective/table_rows/content_for.rb
|
702
|
+
- app/models/effective/table_rows/effective_address.rb
|
703
|
+
- app/models/effective/table_rows/email_field.rb
|
704
|
+
- app/models/effective/table_rows/file_field.rb
|
705
|
+
- app/models/effective/table_rows/percent_field.rb
|
706
|
+
- app/models/effective/table_rows/price_field.rb
|
707
|
+
- app/models/effective/table_rows/text_area.rb
|
708
|
+
- app/models/effective/table_rows/url_field.rb
|
696
709
|
- app/views/action_text/attachables/_content_attachment.html.erb
|
697
710
|
- app/views/action_text/attachables/content_attachments/_horizontal_rule.html.erb
|
698
711
|
- app/views/effective/style_guide/__fields.html.haml
|