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