matestack-ui-bootstrap 1.4.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +17 -5
- data/README.md +53 -19
- data/lib/matestack/ui/bootstrap.rb +97 -17
- data/{app/concepts → lib}/matestack/ui/bootstrap/apps/admin_template.rb +14 -7
- data/lib/matestack/ui/bootstrap/base_component.rb +13 -0
- data/lib/matestack/ui/bootstrap/base_vue_js_component.rb +13 -0
- data/lib/matestack/ui/bootstrap/components/accordion.rb +58 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/alert.js +12 -9
- data/lib/matestack/ui/bootstrap/components/alert.rb +43 -0
- data/lib/matestack/ui/bootstrap/components/avatar.rb +27 -0
- data/lib/matestack/ui/bootstrap/components/badge.rb +32 -0
- data/lib/matestack/ui/bootstrap/components/breadcrumb.rb +50 -0
- data/lib/matestack/ui/bootstrap/components/button.rb +71 -0
- data/lib/matestack/ui/bootstrap/components/button_group.rb +36 -0
- data/lib/matestack/ui/bootstrap/components/card.rb +105 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/carousel.js +21 -18
- data/lib/matestack/ui/bootstrap/components/carousel.rb +103 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/close.rb +10 -9
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/collapse.js +20 -17
- data/lib/matestack/ui/bootstrap/components/collapse.rb +54 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/dropdown.js +5 -2
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/dropdown.rb +31 -26
- data/lib/matestack/ui/bootstrap/components/icon.rb +21 -0
- data/lib/matestack/ui/bootstrap/components/list_group.rb +148 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/modal.js +24 -21
- data/lib/matestack/ui/bootstrap/components/modal.rb +121 -0
- data/lib/matestack/ui/bootstrap/components/navbar.rb +163 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/page_heading.rb +7 -5
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/pagination.rb +15 -13
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/popover.js +4 -1
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/popover.rb +26 -22
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/progress.rb +24 -24
- data/lib/matestack/ui/bootstrap/components/scrollspy.rb +50 -0
- data/lib/matestack/ui/bootstrap/components/section_card.rb +33 -0
- data/lib/matestack/ui/bootstrap/components/spinner.rb +35 -0
- data/lib/matestack/ui/bootstrap/components/tab_nav.rb +79 -0
- data/lib/matestack/ui/bootstrap/components/tab_nav_content.rb +35 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/toast.js +27 -18
- data/lib/matestack/ui/bootstrap/components/toast.rb +113 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/components/tooltip.js +4 -1
- data/lib/matestack/ui/bootstrap/components/tooltip.rb +66 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/content/figure.rb +4 -2
- data/lib/matestack/ui/bootstrap/content/smart_collection/collection.rb +120 -0
- data/{app/concepts/matestack/ui/bootstrap/content/collection → lib/matestack/ui/bootstrap/content/smart_collection}/collection.scss +0 -0
- data/lib/matestack/ui/bootstrap/content/smart_collection/content.rb +118 -0
- data/{app/concepts/matestack/ui/bootstrap/content/collection → lib/matestack/ui/bootstrap/content/smart_collection}/filter.rb +7 -3
- data/{app/concepts/matestack/ui/bootstrap/content/collection → lib/matestack/ui/bootstrap/content/smart_collection}/paginate.rb +19 -14
- data/lib/matestack/ui/bootstrap/form/checkbox.rb +90 -0
- data/lib/matestack/ui/bootstrap/form/input.rb +118 -0
- data/lib/matestack/ui/bootstrap/form/radio.rb +57 -0
- data/lib/matestack/ui/bootstrap/form/select.rb +63 -0
- data/lib/matestack/ui/bootstrap/form/submit.rb +20 -0
- data/lib/matestack/ui/bootstrap/form/switch.rb +32 -0
- data/lib/matestack/ui/bootstrap/form/textarea.rb +49 -0
- data/lib/matestack/ui/bootstrap/index.js +24 -0
- data/lib/matestack/ui/bootstrap/layout/column.rb +49 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/layout/container.rb +12 -9
- data/lib/matestack/ui/bootstrap/layout/row.rb +25 -0
- data/{app/concepts → lib}/matestack/ui/bootstrap/layout/sidebar.js +5 -2
- data/{app/concepts → lib}/matestack/ui/bootstrap/layout/sidebar.rb +10 -10
- data/{app/concepts → lib}/matestack/ui/bootstrap/layout/sidebar.scss +0 -0
- data/lib/matestack/ui/bootstrap/registry.rb +173 -0
- data/{app/javascript/matestack-ui-bootstrap → lib/matestack/ui/bootstrap}/stylesheets/matestack-ui-bootstrap.scss +0 -0
- data/lib/matestack/ui/bootstrap/version.rb +1 -1
- data/lib/tasks/matestack/ui/bootstrap_tasks.rake +25 -25
- metadata +68 -76
- data/app/assets/images/avatar-placeholder.png +0 -0
- data/app/assets/images/icons/bootstrap-icons.svg +0 -1
- data/app/concepts/matestack/ui/bootstrap/components/accordion.rb +0 -53
- data/app/concepts/matestack/ui/bootstrap/components/alert.rb +0 -34
- data/app/concepts/matestack/ui/bootstrap/components/avatar.rb +0 -27
- data/app/concepts/matestack/ui/bootstrap/components/badge.rb +0 -30
- data/app/concepts/matestack/ui/bootstrap/components/breadcrumb.rb +0 -46
- data/app/concepts/matestack/ui/bootstrap/components/button.rb +0 -54
- data/app/concepts/matestack/ui/bootstrap/components/button_group.rb +0 -36
- data/app/concepts/matestack/ui/bootstrap/components/card.rb +0 -100
- data/app/concepts/matestack/ui/bootstrap/components/carousel.rb +0 -85
- data/app/concepts/matestack/ui/bootstrap/components/chart.js +0 -232
- data/app/concepts/matestack/ui/bootstrap/components/chart.rb +0 -71
- data/app/concepts/matestack/ui/bootstrap/components/collapse.rb +0 -43
- data/app/concepts/matestack/ui/bootstrap/components/icon.rb +0 -19
- data/app/concepts/matestack/ui/bootstrap/components/list_group.rb +0 -83
- data/app/concepts/matestack/ui/bootstrap/components/modal.rb +0 -106
- data/app/concepts/matestack/ui/bootstrap/components/navbar.rb +0 -120
- data/app/concepts/matestack/ui/bootstrap/components/scrollspy.rb +0 -33
- data/app/concepts/matestack/ui/bootstrap/components/section_card.rb +0 -31
- data/app/concepts/matestack/ui/bootstrap/components/spinner.rb +0 -31
- data/app/concepts/matestack/ui/bootstrap/components/tab_nav.rb +0 -81
- data/app/concepts/matestack/ui/bootstrap/components/tab_nav_content.rb +0 -32
- data/app/concepts/matestack/ui/bootstrap/components/toast.rb +0 -99
- data/app/concepts/matestack/ui/bootstrap/components/tooltip.rb +0 -82
- data/app/concepts/matestack/ui/bootstrap/content/collection/collection.rb +0 -112
- data/app/concepts/matestack/ui/bootstrap/content/collection/content.rb +0 -101
- data/app/concepts/matestack/ui/bootstrap/form/checkbox.rb +0 -90
- data/app/concepts/matestack/ui/bootstrap/form/date.js +0 -38
- data/app/concepts/matestack/ui/bootstrap/form/date.rb +0 -98
- data/app/concepts/matestack/ui/bootstrap/form/input.rb +0 -123
- data/app/concepts/matestack/ui/bootstrap/form/radio.rb +0 -65
- data/app/concepts/matestack/ui/bootstrap/form/select.haml +0 -11
- data/app/concepts/matestack/ui/bootstrap/form/select.rb +0 -74
- data/app/concepts/matestack/ui/bootstrap/form/submit.rb +0 -20
- data/app/concepts/matestack/ui/bootstrap/form/switch.rb +0 -90
- data/app/concepts/matestack/ui/bootstrap/layout/column.rb +0 -47
- data/app/concepts/matestack/ui/bootstrap/layout/row.rb +0 -15
- data/app/concepts/matestack/ui/bootstrap/pages/devise/sign_in.rb +0 -40
- data/app/concepts/matestack/ui/bootstrap/registry.rb +0 -63
- data/app/helpers/matestack/ui/bootstrap/application_helper.rb +0 -13
- data/app/javascript/matestack-ui-bootstrap/index.js +0 -26
- data/app/javascript/packs/matestack-ui-bootstrap.js +0 -2
- data/config/routes.rb +0 -2
- data/lib/matestack/ui/bootstrap/engine.rb +0 -26
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative "../base_vue_js_component"
|
2
|
+
|
3
|
+
class Matestack::Ui::Bootstrap::Components::Toast < Matestack::Ui::Bootstrap::BaseVueJsComponent
|
4
|
+
vue_name "matestack-ui-bootstrap-toast"
|
5
|
+
|
6
|
+
# header attributes, expects a hash or string
|
7
|
+
# possible keys `:icon_class, :icon, :title, :subtitle`
|
8
|
+
optional :header
|
9
|
+
# body expects a string as message inside toast
|
10
|
+
optional :body
|
11
|
+
# placement attributes, expects a hash wiht possible keys: position, min-height
|
12
|
+
optional :placement # for adding custom css style
|
13
|
+
optional :important, :delay, :autohide, :animation
|
14
|
+
optional class: { as: :bs_class }
|
15
|
+
optional :attributes, :data
|
16
|
+
|
17
|
+
|
18
|
+
optional :show_on, :hide_on, :dispose_on
|
19
|
+
|
20
|
+
def response
|
21
|
+
standard_placement_partial
|
22
|
+
# standard_placement_partial unless placement.present?
|
23
|
+
# custom_placement_partial if placement.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def vue_props
|
29
|
+
{}.tap do |props|
|
30
|
+
props[:delay] = context.delay
|
31
|
+
props[:autohide] = context.autohide
|
32
|
+
props[:show_on] = context.show_on
|
33
|
+
props[:hide_on] = context.hide_on
|
34
|
+
props[:dispose_on] = context.dispose_on
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def custom_placement_partial
|
39
|
+
div placement_attrs do
|
40
|
+
standard_placement_partial
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def standard_placement_partial
|
45
|
+
div toast_attributes do
|
46
|
+
header_partial if context.header || slots && slots[:header]
|
47
|
+
body_partial
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def header_partial
|
52
|
+
header = context.header.is_a?(Hash) ? context.header : { title: context.header }
|
53
|
+
div class: "toast-header" do
|
54
|
+
img class: "#{'rounded me-2' || header[:icon_class]}", path: header[:icon] if header[:icon].present?
|
55
|
+
strong header[:title], class: "me-auto" if header[:title].present?
|
56
|
+
small header[:subtitle] if header[:subtitle].present?
|
57
|
+
|
58
|
+
slot :header if slots && slots[:header]
|
59
|
+
bs_close dismiss: 'toast', class: "ms-2 mb-1", "@click": "hide()"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def body_partial
|
65
|
+
div class: "toast-body" do
|
66
|
+
plain context.body if context.body
|
67
|
+
end
|
68
|
+
unless context.header || slots && slots[:header]
|
69
|
+
bs_close dismiss: 'toast', class: "ms-auto me-2 btn-close-white", "@click": "hide()"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def toast_attributes
|
74
|
+
options.merge(
|
75
|
+
class: toast_classes,
|
76
|
+
data: toast_data
|
77
|
+
).merge(toast_attrs)
|
78
|
+
end
|
79
|
+
|
80
|
+
def toast_data
|
81
|
+
(context.data || {}).tap do |hash|
|
82
|
+
hash["bs-delay"] = context.delay.nil? ? 5000 : context.delay
|
83
|
+
hash["bs-autohide"] = context.autohide.nil? ? "true" : "#{context.autohide}"
|
84
|
+
hash["bs-animation"] = context.animation.nil? ? "true" : "#{context.animation}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def toast_attrs
|
89
|
+
(context.attributes || {}).tap do |hash|
|
90
|
+
hash[:role] = (context.important == false ? 'status' : 'alert')
|
91
|
+
hash[:'aria-live'] = (context.important ? 'assertive' : 'polite') if context.important.present? && !context.placement.present?
|
92
|
+
hash[:'aria-live'] = 'assertive' unless context.important.present?
|
93
|
+
hash[:'aria-atomic'] = 'true' unless context.placement.present?
|
94
|
+
hash[:style] = "z-index: 10000; position: fixed; #{context.placement[:position] || 'top: 0; right: 0;' }" if context.placement.present?
|
95
|
+
hash[:"v-bind:class"] = "{'show' : showing }"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def toast_classes
|
100
|
+
[].tap do |classes|
|
101
|
+
classes << 'toast p-0 fade d-flex align-items-center border-0'
|
102
|
+
classes << context.bs_class
|
103
|
+
end.join(' ').strip
|
104
|
+
end
|
105
|
+
|
106
|
+
def placement_attrs
|
107
|
+
{}.tap do |hash|
|
108
|
+
hash[:'aria-live'] = (context.important ? 'assertive' : 'polite') if context.important.present?
|
109
|
+
hash[:'aria-atomic'] = 'true'
|
110
|
+
hash[:style] = "position: relative; min-height: #{context.placement[:height]};"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
import * as bootstrap from 'bootstrap'
|
2
|
+
import Vue from 'vue/dist/vue.esm'
|
2
3
|
|
3
|
-
MatestackUiCore
|
4
|
+
import MatestackUiCore from 'matestack-ui-core'
|
5
|
+
|
6
|
+
Vue.component('matestack-ui-bootstrap-tooltip', {
|
4
7
|
|
5
8
|
mixins: [MatestackUiCore.componentMixin],
|
6
9
|
data() {
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative "../base_vue_js_component"
|
2
|
+
|
3
|
+
class Matestack::Ui::Bootstrap::Components::Tooltip < Matestack::Ui::Bootstrap::BaseVueJsComponent
|
4
|
+
vue_name "matestack-ui-bootstrap-tooltip"
|
5
|
+
|
6
|
+
DATA_ALIAS_ATTRIBUTES = %i[container delay selector html template fallback_placement]
|
7
|
+
|
8
|
+
DATA_ALIAS_ATTRIBUTES.each do |attribute|
|
9
|
+
optional :"#{attribute}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO:
|
13
|
+
# for security reasons the sanitize, sanitizeFn and whiteList options cannot be supplied using data attributes.
|
14
|
+
# sanitize sanitize_fn white_list
|
15
|
+
# optional :content
|
16
|
+
required :tooltip_title
|
17
|
+
optional :tag
|
18
|
+
optional class: { as: :bs_class }
|
19
|
+
optional :id
|
20
|
+
DATA_ATTRIBUTES = %i[text variant animation placement tabindex trigger boundary offset popper_config]
|
21
|
+
optional *DATA_ATTRIBUTES
|
22
|
+
|
23
|
+
def response
|
24
|
+
case context.tag
|
25
|
+
when :div
|
26
|
+
div tooltip_attributes do
|
27
|
+
yield if block_given?
|
28
|
+
end
|
29
|
+
else
|
30
|
+
span tooltip_attributes do
|
31
|
+
yield if block_given?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def tooltip_attributes
|
39
|
+
attributes = {}.tap do |hash|
|
40
|
+
hash[:class] = tooltip_classes
|
41
|
+
hash[:text] = context.text if context.text.present?
|
42
|
+
hash[:data] = {}.tap do |hash|
|
43
|
+
DATA_ALIAS_ATTRIBUTES.each do |attribute|
|
44
|
+
hash["bs-#{attribute}"] = context.send("#{attribute}") if context.send("#{attribute}")
|
45
|
+
end
|
46
|
+
DATA_ATTRIBUTES.each do |attribute|
|
47
|
+
hash["bs-#{attribute}"] = context.send("#{attribute}") if context.send("#{attribute}")
|
48
|
+
end
|
49
|
+
hash["bs-toggle"] = "tooltip"
|
50
|
+
hash["bs-type"] = context.tag
|
51
|
+
hash["bs-placement"] = "auto" if context.placement.nil?
|
52
|
+
hash["bs-title"] = context.tooltip_title
|
53
|
+
end
|
54
|
+
end
|
55
|
+
options.merge(
|
56
|
+
attributes || {}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def tooltip_classes
|
61
|
+
[].tap do |classes|
|
62
|
+
classes << context.bs_class
|
63
|
+
end.join(' ').strip
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
1
|
+
require_relative "../base_component"
|
2
|
+
|
3
|
+
class Matestack::Ui::Bootstrap::Content::Figure < Matestack::Ui::Bootstrap::BaseComponent
|
2
4
|
|
3
5
|
def response
|
4
6
|
# provide a bootstrap figure
|
5
7
|
end
|
6
8
|
|
7
|
-
end
|
9
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require_relative "../../base_component"
|
2
|
+
|
3
|
+
require_relative "./content"
|
4
|
+
require_relative "./filter"
|
5
|
+
require_relative "./paginate"
|
6
|
+
|
7
|
+
class Matestack::Ui::Bootstrap::Content::SmartCollection::Collection < Matestack::Ui::Bootstrap::BaseComponent
|
8
|
+
include Matestack::Ui::VueJs::Components::Collection::Helper
|
9
|
+
include Matestack::Ui::Bootstrap::Content::SmartCollection::Content
|
10
|
+
include Matestack::Ui::Bootstrap::Content::SmartCollection::Filter
|
11
|
+
include Matestack::Ui::Bootstrap::Content::SmartCollection::Paginate
|
12
|
+
|
13
|
+
# html attributes
|
14
|
+
optional :id
|
15
|
+
|
16
|
+
# table configuration
|
17
|
+
optional :items
|
18
|
+
optional :columns
|
19
|
+
optional :filters
|
20
|
+
optional :footer
|
21
|
+
optional :paginate
|
22
|
+
optional :rerender_on
|
23
|
+
optional :item_actions_proc
|
24
|
+
optional :collection_rendering_proc
|
25
|
+
|
26
|
+
|
27
|
+
# bootstrap settings
|
28
|
+
optional :responsive
|
29
|
+
optional :variant
|
30
|
+
optional :striped
|
31
|
+
optional :hoverable
|
32
|
+
optional :border_variant
|
33
|
+
optional :borderless
|
34
|
+
|
35
|
+
attr_accessor :processed_filters
|
36
|
+
|
37
|
+
def response
|
38
|
+
div id: context.id, class: "smart-collection" do
|
39
|
+
filter_partial
|
40
|
+
content
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def collection
|
48
|
+
return @collection if @collection
|
49
|
+
settings = {}.tap do |h|
|
50
|
+
h[:id] = context.id || "smartcollection"
|
51
|
+
h[:data] = filtered_query
|
52
|
+
h[:base_count] = context.items.count
|
53
|
+
h[:init_limit] = context.paginate if context.paginate
|
54
|
+
h[:filtered_count] = filtered_query.count if context.paginate
|
55
|
+
end
|
56
|
+
@collection = set_collection(settings)
|
57
|
+
end
|
58
|
+
|
59
|
+
def collection_id
|
60
|
+
collection.config[:id]
|
61
|
+
end
|
62
|
+
|
63
|
+
def filtered_query
|
64
|
+
return @filtered_query if @filtered_query
|
65
|
+
@filtered_query = context.items
|
66
|
+
unless context.filters.nil?
|
67
|
+
context.filters.select { |key, value| '.'.in? key.to_s }.each do |key, value|
|
68
|
+
associated_name = key.to_s.split(".").first
|
69
|
+
@filtered_query = @filtered_query.joins(associated_name.to_sym).all
|
70
|
+
if value.is_a?(Hash)
|
71
|
+
processed_filters[key] = value
|
72
|
+
@filtered_query = add_query_filter(@filtered_query, associated_name, key, value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
context.filters.reject { |key, value| '.'.in? key.to_s }.each do |key, value|
|
76
|
+
if value.is_a?(Hash)
|
77
|
+
processed_filters[key] = value
|
78
|
+
@filtered_query = add_query_filter(@filtered_query, nil, key, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@filtered_query
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_query_filter(query, associated_name, key, filter_config)
|
86
|
+
value = get_collection_filter(collection_id)[key.to_sym]
|
87
|
+
if value.present?
|
88
|
+
if associated_name.present?
|
89
|
+
table_name = context.items.klass.reflections[associated_name].table_name
|
90
|
+
key = key.to_s.gsub(associated_name, table_name)
|
91
|
+
else
|
92
|
+
table_name = context.items.klass.table_name
|
93
|
+
key = key.to_s
|
94
|
+
end
|
95
|
+
case filter_config[:match]
|
96
|
+
when :equals
|
97
|
+
query = query.where("#{key}": value)
|
98
|
+
when :starts_with
|
99
|
+
query = query.where("lower(#{key}) LIKE ?", "#{value.downcase}%")
|
100
|
+
when :ends_with
|
101
|
+
query = query.where("lower(#{key}) LIKE ?", "%#{value.downcase}")
|
102
|
+
when :like
|
103
|
+
query = query.where("lower(#{key}) LIKE ?", "%#{value.downcase}%")
|
104
|
+
else
|
105
|
+
query = query.where("#{key}": value)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
query
|
109
|
+
end
|
110
|
+
|
111
|
+
def head_columns
|
112
|
+
context.columns.map { |key, value| value.is_a?(Hash) ? value[:heading] : value }
|
113
|
+
end
|
114
|
+
|
115
|
+
def processed_filters
|
116
|
+
@filters ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
end
|
File without changes
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Matestack::Ui::Bootstrap::Content::SmartCollection::Content
|
2
|
+
|
3
|
+
def content
|
4
|
+
bs_row class: 'smart-collection-content' do
|
5
|
+
bs_col do
|
6
|
+
async id: "#{collection_id}-async", rerender_on: "#{collection_id}-update, #{context.rerender_on} " do
|
7
|
+
collection_content collection.config do
|
8
|
+
div class: responsive_class do
|
9
|
+
if slots && slots[:collection_rendering]
|
10
|
+
slot :collection_rendering, collection.paginated_data
|
11
|
+
elsif context.columns
|
12
|
+
div class: "table-responsive" do
|
13
|
+
table table_attributes do
|
14
|
+
table_head
|
15
|
+
table_body
|
16
|
+
table_footer
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
paginate_partial if context.paginate.present?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def table_head
|
29
|
+
thead do
|
30
|
+
tr do
|
31
|
+
context.columns&.each do |key, value|
|
32
|
+
th class: cell_class(value), scope: :col do
|
33
|
+
plain value.is_a?(Hash) ? value[:heading] : value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
th if slots && slots[:table_item_actions]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def table_body
|
42
|
+
tbody do
|
43
|
+
collection.paginated_data.each_with_index do |data, index|
|
44
|
+
tr class: 'align-middle' do
|
45
|
+
context.columns.each do |key, value|
|
46
|
+
cell(data, key, value)
|
47
|
+
end
|
48
|
+
if slots && slots[:table_item_actions]
|
49
|
+
td class: 'text-end' do
|
50
|
+
slot :table_item_actions, data
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def table_footer
|
59
|
+
tfoot do
|
60
|
+
tr do
|
61
|
+
context.footer&.each do |value|
|
62
|
+
td value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end if context.footer
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def cell(data, key, value)
|
71
|
+
td class: cell_class(value) do
|
72
|
+
if value.is_a?(Hash) && value[:slot]
|
73
|
+
value[:slot].call(data)
|
74
|
+
else
|
75
|
+
plain cell_text(data, key, value)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def cell_class(value)
|
81
|
+
[].tap do |classes|
|
82
|
+
classes << "text-#{value[:text]}" if value[:text]
|
83
|
+
classes << "align-#{value[:align]}" if value[:align]
|
84
|
+
end.join(' ') if value.is_a? Hash
|
85
|
+
end
|
86
|
+
|
87
|
+
def cell_text(data, key, value)
|
88
|
+
if value.is_a?(Hash)
|
89
|
+
if value[:attribute].present?
|
90
|
+
text = data.instance_eval(value[:attribute].to_s)
|
91
|
+
else
|
92
|
+
text = data.instance_eval(key.to_s)
|
93
|
+
end
|
94
|
+
text = value[:format].call(text) if value[:format].present?
|
95
|
+
else
|
96
|
+
text = data.instance_eval(key.to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
text
|
100
|
+
end
|
101
|
+
|
102
|
+
def table_attributes
|
103
|
+
klass = ['table'].tap do |classes|
|
104
|
+
classes << "table-#{context.variant}" if context.variant
|
105
|
+
classes << "table-striped" if context.striped
|
106
|
+
classes << "table-hover" if context.hoverable
|
107
|
+
classes << "table-bordered border-#{context.border_variant}" if context.border_variant
|
108
|
+
classes << "table-borderless" if context.borderless
|
109
|
+
end.join(' ').strip
|
110
|
+
{ id: collection_id, class: klass }
|
111
|
+
end
|
112
|
+
|
113
|
+
def responsive_class
|
114
|
+
return unless context.responsive
|
115
|
+
responsive === true ? 'table-responsive' : "table-responsive-#{context.responsive}"
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|