effective_datatables 3.6.3 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/app/assets/javascripts/dataTables/locales/en.lang +33 -0
- data/app/assets/javascripts/dataTables/locales/es.lang +36 -0
- data/app/assets/javascripts/dataTables/locales/nl.lang +30 -0
- data/app/assets/javascripts/effective_datatables/filters.js.coffee +1 -0
- data/app/assets/javascripts/effective_datatables/flash.js.coffee +31 -0
- data/app/assets/javascripts/effective_datatables/initialize.js.coffee +41 -53
- data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +217 -0
- data/app/assets/javascripts/effective_datatables/overrides.js.coffee +7 -0
- data/app/assets/javascripts/effective_datatables/reorder.js.coffee +43 -0
- data/app/assets/javascripts/effective_datatables/reset.js.coffee +1 -1
- data/app/assets/stylesheets/effective_datatables/_overrides.scss +28 -0
- data/app/controllers/effective/datatables_controller.rb +39 -6
- data/app/datatables/effective_style_guide_datatable.rb +47 -0
- data/app/helpers/effective_datatables_helper.rb +49 -56
- data/app/helpers/effective_datatables_private_helper.rb +137 -11
- data/app/models/effective/datatable.rb +36 -16
- data/app/models/effective/datatable_column.rb +1 -0
- data/app/models/effective/datatable_value_tool.rb +20 -20
- data/app/models/effective/effective_datatable/attributes.rb +5 -13
- data/app/models/effective/effective_datatable/collection.rb +18 -3
- data/app/models/effective/effective_datatable/compute.rb +15 -6
- data/app/models/effective/effective_datatable/cookie.rb +19 -18
- data/app/models/effective/effective_datatable/dsl.rb +8 -3
- data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +16 -23
- data/app/models/effective/effective_datatable/dsl/datatable.rb +70 -28
- data/app/models/effective/effective_datatable/dsl/filters.rb +12 -4
- data/app/models/effective/effective_datatable/format.rb +1 -4
- data/app/models/effective/effective_datatable/params.rb +9 -4
- data/app/models/effective/effective_datatable/resource.rb +129 -74
- data/app/models/effective/effective_datatable/state.rb +30 -15
- data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +3 -5
- data/app/views/effective/datatables/_datatable.html.haml +3 -5
- data/app/views/effective/datatables/_filters.html.haml +4 -24
- data/app/views/effective/datatables/_reorder_column.html.haml +5 -0
- data/app/views/effective/style_guide/_effective_datatables.html.haml +1 -0
- data/config/effective_datatables.rb +8 -21
- data/config/locales/en.yml +12 -0
- data/config/locales/es.yml +12 -0
- data/config/locales/nl.yml +12 -0
- data/config/routes.rb +5 -4
- data/lib/effective_datatables.rb +49 -2
- data/lib/effective_datatables/engine.rb +4 -2
- data/lib/effective_datatables/version.rb +1 -1
- metadata +17 -5
- data/app/views/effective/datatables/_reset.html.haml +0 -2
@@ -0,0 +1,43 @@
|
|
1
|
+
reorder = (event, diff, edit) ->
|
2
|
+
change = diff.find (obj) -> obj.node == edit.triggerRow.node()
|
3
|
+
return unless change?
|
4
|
+
|
5
|
+
$table = $(event.currentTarget)
|
6
|
+
oldNode = $("<div>#{change.oldData}</div>").find('input[data-reorder-resource]')
|
7
|
+
newNode = $("<div>#{change.newData}</div>").find('input[data-reorder-resource]')
|
8
|
+
return unless oldNode? && newNode?
|
9
|
+
|
10
|
+
url = @context[0].ajax.url.replace('.json', '/reorder.json')
|
11
|
+
data = {'reorder[id]': oldNode.data('reorder-resource'), 'reorder[old]': oldNode.val(), 'reorder[new]': newNode.val(), attributes: $table.data('attributes') }
|
12
|
+
|
13
|
+
@context[0].rowreorder.c.enable = false
|
14
|
+
|
15
|
+
$.ajax(
|
16
|
+
method: 'post',
|
17
|
+
url: url,
|
18
|
+
data: data,
|
19
|
+
async: false
|
20
|
+
).fail((response, text, status) =>
|
21
|
+
$(event.target).closest('table').DataTable().flash(status, 'danger')
|
22
|
+
).always((response) =>
|
23
|
+
@context[0].rowreorder.c.enable = true
|
24
|
+
)
|
25
|
+
|
26
|
+
$.fn.DataTable.Api.register('reorder()', reorder);
|
27
|
+
|
28
|
+
$(document).on 'click', '.dataTables_wrapper a.buttons-reorder', (event) ->
|
29
|
+
event.preventDefault() # prevent the click
|
30
|
+
|
31
|
+
$link = $(event.currentTarget)
|
32
|
+
$table = $link.closest('.dataTables_wrapper').find('table.dataTable').first()
|
33
|
+
|
34
|
+
column = $table.DataTable().column('.col-_reorder')
|
35
|
+
return unless column.length > 0
|
36
|
+
|
37
|
+
if column.visible()
|
38
|
+
$table.removeClass('reordering')
|
39
|
+
else
|
40
|
+
$table.addClass('reordering')
|
41
|
+
|
42
|
+
column.visible(!column.visible())
|
43
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
$(document).on 'click', 'a.buttons-reset-search', (event) ->
|
1
|
+
$(document).on 'click', '.dataTables_wrapper a.buttons-reset-search', (event) ->
|
2
2
|
event.preventDefault() # prevent the click
|
3
3
|
|
4
4
|
$table = $(event.currentTarget).closest('.dataTables_wrapper').find('table.dataTable').first()
|
@@ -35,6 +35,8 @@ table.dataTable thead {
|
|
35
35
|
border-bottom: none;
|
36
36
|
white-space: nowrap;
|
37
37
|
padding: 6px;
|
38
|
+
|
39
|
+
span { display: block; }
|
38
40
|
}
|
39
41
|
|
40
42
|
.form-control, .form-group {
|
@@ -194,3 +196,29 @@ table.dataTable {
|
|
194
196
|
p { margin-bottom: 0px; }
|
195
197
|
}
|
196
198
|
}
|
199
|
+
|
200
|
+
// Simple styles
|
201
|
+
table.dataTable.hide-sort > thead {
|
202
|
+
.sorting { background-image: none; cursor: default; }
|
203
|
+
.sorting_asc { background-image: none; cursor: default; }
|
204
|
+
.sorting_desc { background-image: none; cursor: default; }
|
205
|
+
}
|
206
|
+
|
207
|
+
table.dataTable.hide-search > thead {
|
208
|
+
.form-group { display: none; }
|
209
|
+
}
|
210
|
+
|
211
|
+
table.dataTable.hide-buttons {
|
212
|
+
.col-bulk_actions { display: none; }
|
213
|
+
}
|
214
|
+
|
215
|
+
// Datatables entries
|
216
|
+
@media screen and (max-width: 767px) {
|
217
|
+
div.dataTables_wrapper div.dataTables_entries { text-align: center; }
|
218
|
+
}
|
219
|
+
|
220
|
+
.dataTables_buttons {
|
221
|
+
.buttons-bulk-actions {
|
222
|
+
button { font-size: 12px; }
|
223
|
+
}
|
224
|
+
}
|
@@ -5,7 +5,7 @@ module Effective
|
|
5
5
|
# This will respond to both a GET and a POST
|
6
6
|
def show
|
7
7
|
begin
|
8
|
-
@datatable =
|
8
|
+
@datatable = EffectiveDatatables.find(params[:id], params[:attributes])
|
9
9
|
@datatable.view = view_context
|
10
10
|
|
11
11
|
EffectiveDatatables.authorize!(self, :index, @datatable.collection_class)
|
@@ -13,18 +13,51 @@ module Effective
|
|
13
13
|
render json: @datatable.to_json
|
14
14
|
rescue => e
|
15
15
|
EffectiveDatatables.authorized?(self, :index, @datatable.try(:collection_class))
|
16
|
-
|
17
16
|
render json: error_json(e)
|
17
|
+
|
18
|
+
ExceptionNotifier.notify_exception(e) if defined?(ExceptionNotifier)
|
19
|
+
raise e if Rails.env.development?
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
|
23
|
+
def reorder
|
24
|
+
begin
|
25
|
+
@datatable = EffectiveDatatables.find(params[:id], params[:attributes])
|
26
|
+
@datatable.view = view_context
|
27
|
+
|
28
|
+
EffectiveDatatables.authorize!(self, :index, @datatable.collection_class)
|
29
|
+
|
30
|
+
@resource = @datatable.collection.find(params[:reorder][:id])
|
31
|
+
|
32
|
+
EffectiveDatatables.authorize!(self, :update, @resource)
|
33
|
+
|
34
|
+
attribute = @datatable.columns[:_reorder][:reorder]
|
35
|
+
old_index = params[:reorder][:old].to_i
|
36
|
+
new_index = params[:reorder][:new].to_i
|
37
|
+
|
38
|
+
@resource.class.transaction do
|
39
|
+
if new_index > old_index
|
40
|
+
@datatable.collection.where("#{attribute} > ? AND #{attribute} <= ?", old_index, new_index).update_all("#{attribute} = #{attribute} - 1")
|
41
|
+
@resource.update_column(attribute, new_index)
|
42
|
+
end
|
43
|
+
|
44
|
+
if old_index > new_index
|
45
|
+
@datatable.collection.where("#{attribute} >= ? AND #{attribute} < ?", new_index, old_index).update_all("#{attribute} = #{attribute} + 1")
|
46
|
+
@resource.update_column(attribute, new_index)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
render status: :ok, body: :ok
|
51
|
+
rescue Effective::AccessDenied => e
|
52
|
+
render(status: :unauthorized, body: 'Access Denied')
|
53
|
+
rescue => e
|
54
|
+
render(status: :error, body: 'Unexpected Error')
|
55
|
+
end
|
22
56
|
|
23
|
-
def find_datatable(id)
|
24
|
-
id = id.to_s.gsub(/-\d+\z/, '').gsub('-', '/')
|
25
|
-
id.classify.safe_constantize || id.classify.pluralize.safe_constantize
|
26
57
|
end
|
27
58
|
|
59
|
+
private
|
60
|
+
|
28
61
|
def error_json(e)
|
29
62
|
{
|
30
63
|
data: [],
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class EffectiveStyleGuideDatatable < Effective::Datatable
|
2
|
+
datatable do
|
3
|
+
length 10
|
4
|
+
|
5
|
+
col :id
|
6
|
+
col :material, search: { collection: ['Stainless Steel', 'Copper', 'Cast Iron', 'Composite'] }
|
7
|
+
col :bowl, search: { collection: ['Single Bowl', 'Double Bowl', 'Triple Bowl'] }
|
8
|
+
col :name
|
9
|
+
col :date, as: :date
|
10
|
+
|
11
|
+
actions_col
|
12
|
+
end
|
13
|
+
|
14
|
+
# Set the permission check to the same as Effective::StyleGuide
|
15
|
+
def collection_class
|
16
|
+
defined?(Effective::StyleGuide) ? Effective::StyleGuide : super
|
17
|
+
end
|
18
|
+
|
19
|
+
collection do
|
20
|
+
now = Time.zone.now
|
21
|
+
[
|
22
|
+
[1, 'Stainless Steel', 'Single Bowl', 'KOHLER Staccato', (now + 1.day)],
|
23
|
+
[2, 'Stainless Steel', 'Double Bowl', 'KOHLER Vault Undercounter', (now + 1.day)],
|
24
|
+
[3, 'Stainless Steel', 'Triple Bowl', 'KRAUS All-In-One', (now + 1.day)],
|
25
|
+
[4, 'Stainless Steel', 'Single Bowl', 'KOHLER Vault Dual Mount', (now + 1.day)],
|
26
|
+
[5, 'Stainless Steel', 'Single Bowl', 'KRAUS All-In-One Undermount', (now + 2.days)],
|
27
|
+
[6, 'Stainless Steel', 'Double Bowl', 'Glacier Bay All-in-One', (now + 2.days)],
|
28
|
+
[7, 'Stainless Steel', 'Single Bowl', 'Elkay Neptune', (now + 2.days)],
|
29
|
+
[8, 'Copper', 'Single Bowl', 'ECOSINKS Apron Front Dual Mount', (now + 2.days)],
|
30
|
+
[9, 'Copper', 'Double Bowl', 'ECOSINKS Dual Mount Front Hammered', (now + 2.days)],
|
31
|
+
[10, 'Copper', 'Triple Bowl', 'Glarier Bay Undermount', (now + 3.days)],
|
32
|
+
[11, 'Copper', 'Single Bowl', 'Whitehaus Undermount', (now + 3.days)],
|
33
|
+
[12, 'Copper', 'Double Bowl', 'Belle Foret Apron Front', (now + 3.days)],
|
34
|
+
[13, 'Copper', 'Double Bowl', 'Pegasus Dual Mount', (now + 3.days)],
|
35
|
+
[14, 'Cast Iron', 'Double Bowl', 'KOHLER Whitehaven', (now + 3.days)],
|
36
|
+
[15, 'Cast Iron', 'Triple Bowl', 'KOHLER Hartland', (now + 3.days)],
|
37
|
+
[16, 'Cast Iron', 'Single Bowl', 'KOHLER Cape Dory Undercounter', (now + 4.days)],
|
38
|
+
[17, 'Cast Iron', 'Double Bowl', 'KOLER Bakersfield', (now + 4.days)],
|
39
|
+
[18, 'Cast Iron', 'Double Bowl', 'American Standard Offset', (now + 4.days)],
|
40
|
+
[19, 'Cast Iron', 'Single Bowl', 'Brookfield Top', (now + 4.days)],
|
41
|
+
[20, 'Composite', 'Single Bowl', 'Blanco Diamond Undermount', (now + 5.days)],
|
42
|
+
[21, 'Composite', 'Double Bowl', 'Mont Blanc Waterbrook', (now + 5.days)],
|
43
|
+
[22, 'Composite', 'Triple Bowl', 'Pegasus Triple Mount', (now + 5.days)],
|
44
|
+
[23, 'Composite', 'Single Bowl', 'Swanstone Dual Mount', (now + 5.days)]
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
@@ -1,8 +1,15 @@
|
|
1
1
|
# These are expected to be called by a developer. They are part of the datatables DSL.
|
2
2
|
module EffectiveDatatablesHelper
|
3
|
-
|
4
|
-
def render_datatable(datatable, input_js: {}, buttons: true, charts: true, filters: true, simple: false)
|
3
|
+
def render_datatable(datatable, input_js: {}, buttons: true, charts: true, entries: true, filters: true, inline: false, pagination: true, search: true, simple: false, sort: true)
|
5
4
|
raise 'expected datatable to be present' unless datatable
|
5
|
+
raise 'expected input_js to be a Hash' unless input_js.kind_of?(Hash)
|
6
|
+
|
7
|
+
if simple
|
8
|
+
buttons = charts = entries = filters = pagination = search = sort = false
|
9
|
+
end
|
10
|
+
|
11
|
+
datatable.attributes[:inline] = true if inline
|
12
|
+
datatable.attributes[:sortable] = false unless sort
|
6
13
|
|
7
14
|
datatable.view ||= self
|
8
15
|
|
@@ -13,31 +20,48 @@ module EffectiveDatatablesHelper
|
|
13
20
|
charts = charts && datatable._charts.present?
|
14
21
|
filters = filters && (datatable._scopes.present? || datatable._filters.present?)
|
15
22
|
|
16
|
-
datatable.
|
17
|
-
|
23
|
+
html_class = ['effective-datatable', datatable.html_class, ('hide-sort' unless sort), ('hide-search' unless search), ('hide-buttons' unless buttons)].compact.join(' ')
|
24
|
+
|
25
|
+
if datatable.reorder? && !buttons
|
26
|
+
buttons = true; input_js[:buttons] = false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Build the datatables DOM option
|
30
|
+
input_js[:dom] ||= [
|
31
|
+
("<'row'<'col-sm-12 dataTables_buttons'B>>" if buttons),
|
32
|
+
"<'row'<'col-sm-12'tr>>",
|
33
|
+
("<'row'" if entries || pagination),
|
34
|
+
("<'col-sm-6 dataTables_entries'il>" if entries),
|
35
|
+
("<'col-sm-6'p>" if pagination),
|
36
|
+
(">" if entries || pagination)
|
37
|
+
].compact.join
|
18
38
|
|
19
39
|
effective_datatable_params = {
|
20
40
|
id: datatable.to_param,
|
21
|
-
class:
|
41
|
+
class: html_class,
|
22
42
|
data: {
|
43
|
+
'attributes' => EffectiveDatatables.encrypt(datatable.attributes),
|
23
44
|
'authenticity-token' => form_authenticity_token,
|
24
|
-
'effective-form-inputs' => defined?(EffectiveFormInputs),
|
25
45
|
'bulk-actions' => datatable_bulk_actions(datatable),
|
26
46
|
'columns' => datatable_columns(datatable),
|
27
|
-
'cookie' => datatable.cookie_key,
|
28
47
|
'display-length' => datatable.display_length,
|
29
|
-
'display-order' =>
|
48
|
+
'display-order' => datatable_display_order(datatable),
|
30
49
|
'display-records' => datatable.to_json[:recordsFiltered],
|
31
50
|
'display-start' => datatable.display_start,
|
32
|
-
'
|
33
|
-
'
|
34
|
-
'
|
51
|
+
'inline' => inline.to_s,
|
52
|
+
'language' => EffectiveDatatables.language(I18n.locale),
|
53
|
+
'options' => input_js.to_json,
|
54
|
+
'reset' => (datatable_reset(datatable) if search),
|
55
|
+
'reorder' => datatable_reorder(datatable),
|
56
|
+
'reorder-index' => (datatable.columns[:_reorder][:index] if datatable.reorder?).to_s,
|
57
|
+
'simple' => simple.to_s,
|
58
|
+
'spinner' => '', # effective_bootstrap
|
35
59
|
'source' => effective_datatables.datatable_path(datatable, {format: 'json'}),
|
36
60
|
'total-records' => datatable.to_json[:recordsTotal]
|
37
61
|
}
|
38
62
|
}
|
39
63
|
|
40
|
-
if (charts || filters)
|
64
|
+
if (charts || filters)
|
41
65
|
output = ''.html_safe
|
42
66
|
|
43
67
|
if charts
|
@@ -60,59 +84,28 @@ module EffectiveDatatablesHelper
|
|
60
84
|
end
|
61
85
|
end
|
62
86
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
datatable.view ||= self
|
67
|
-
|
68
|
-
unless EffectiveDatatables.authorized?(controller, :index, datatable.collection_class)
|
69
|
-
return content_tag(:p, "You are not authorized to view this datatable. (cannot :index, #{datatable.collection_class})")
|
70
|
-
end
|
71
|
-
|
72
|
-
effective_datatable_params = {
|
73
|
-
id: datatable.to_param,
|
74
|
-
class: Array(datatable.table_html_class).join(' '),
|
75
|
-
data: {}
|
76
|
-
}
|
77
|
-
|
78
|
-
render(partial: 'effective/datatables/datatable',
|
79
|
-
locals: { datatable: datatable, effective_datatable_params: effective_datatable_params }
|
80
|
-
)
|
87
|
+
def render_inline_datatable(datatable)
|
88
|
+
render_datatable(datatable, inline: true)
|
81
89
|
end
|
82
90
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
datatable.view ||= self
|
87
|
-
return unless datatable._scopes.present? || datatable._filters.present?
|
88
|
-
|
89
|
-
if datatable._filters_form_required?
|
90
|
-
render partial: 'effective/datatables/filters', locals: { datatable: datatable }
|
91
|
-
else
|
92
|
-
render(partial: 'effective/datatables/filters', locals: { datatable: datatable }).gsub('<form', '<div').gsub('/form>', '/div>').html_safe
|
93
|
-
end
|
94
|
-
|
91
|
+
def render_simple_datatable(datatable)
|
92
|
+
render_datatable(datatable, simple: true)
|
95
93
|
end
|
96
94
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
datatable.view ||= self
|
101
|
-
return unless datatable._charts.present?
|
102
|
-
|
103
|
-
datatable._charts.map { |name, _| render_datatable_chart(datatable, name) }.join.html_safe
|
95
|
+
def inline_datatable?
|
96
|
+
params[:_datatable_id].present? && params[:_datatable_attributes].present?
|
104
97
|
end
|
105
98
|
|
106
|
-
def
|
107
|
-
|
99
|
+
def inline_datatable
|
100
|
+
return nil unless inline_datatable?
|
101
|
+
return @_inline_datatable if @_inline_datatable
|
108
102
|
|
109
|
-
datatable.
|
110
|
-
|
103
|
+
datatable = EffectiveDatatables.find(params[:_datatable_id], params[:_datatable_attributes])
|
104
|
+
datatable.view = self
|
111
105
|
|
112
|
-
|
113
|
-
chart_data = datatable.to_json[:charts][name][:data]
|
106
|
+
EffectiveDatatables.authorize!(self, :index, datatable.collection_class)
|
114
107
|
|
115
|
-
|
108
|
+
@_inline_datatable ||= datatable
|
116
109
|
end
|
117
110
|
|
118
111
|
end
|
@@ -1,21 +1,21 @@
|
|
1
1
|
# These aren't expected to be called by a developer. They are internal methods.
|
2
|
+
# These aren't expected to be called by a developer. They are internal methods.
|
2
3
|
module EffectiveDatatablesPrivateHelper
|
3
4
|
|
4
5
|
# https://datatables.net/reference/option/columns
|
5
6
|
def datatable_columns(datatable)
|
6
|
-
|
7
|
-
simple_form_for(:datatable_search, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| form = f }
|
7
|
+
sortable = datatable.sortable?
|
8
8
|
|
9
9
|
datatable.columns.map do |name, opts|
|
10
10
|
{
|
11
|
-
name: name,
|
12
|
-
title: content_tag(:span, (opts[:label] == false ? '' : opts[:label]), class: 'search-label'),
|
13
11
|
className: opts[:col_class],
|
14
|
-
|
12
|
+
name: name,
|
15
13
|
responsivePriority: opts[:responsive],
|
16
14
|
search: datatable.state[:search][name],
|
17
|
-
|
18
|
-
|
15
|
+
searchHtml: datatable_search_tag(datatable, name, opts),
|
16
|
+
sortable: (opts[:sort] && sortable),
|
17
|
+
title: datatable_label_tag(datatable, name, opts),
|
18
|
+
visible: datatable.state[:visible][name]
|
19
19
|
}
|
20
20
|
end.to_json.html_safe
|
21
21
|
end
|
@@ -26,17 +26,71 @@ module EffectiveDatatablesPrivateHelper
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def datatable_display_order(datatable)
|
30
|
+
(datatable.sortable? ? [datatable.order_index, datatable.order_direction] : false).to_json.html_safe
|
31
|
+
end
|
32
|
+
|
29
33
|
def datatable_reset(datatable)
|
30
|
-
|
34
|
+
link_to(content_tag(:span, t('effective_datatables.reset')), '#', class: 'btn btn-link btn-sm buttons-reset-search')
|
35
|
+
end
|
36
|
+
|
37
|
+
def datatable_reorder(datatable)
|
38
|
+
return unless datatable.reorder? && EffectiveDatatables.authorized?(self, :update, datatable.collection_class)
|
39
|
+
link_to(content_tag(:span, t('effective_datatables.reorder')), '#', class: 'btn btn-link btn-sm buttons-reorder', disabled: true)
|
31
40
|
end
|
32
41
|
|
33
|
-
def
|
42
|
+
def datatable_new_resource_button(datatable, name, column)
|
43
|
+
return unless column[:inline] && (column[:actions][:new] != false)
|
44
|
+
|
45
|
+
action = { action: :new, class: ['btn', column[:btn_class].presence].compact.join(' '), 'data-remote': true }
|
46
|
+
|
47
|
+
if column[:actions][:new].kind_of?(Hash) # This might be active_record_array_collection?
|
48
|
+
action = action.merge(column[:actions][:new])
|
49
|
+
|
50
|
+
effective_resource = (datatable.effective_resource || datatable.fallback_effective_resource)
|
51
|
+
klass = (column[:actions][:new][:klass] || effective_resource&.klass || datatable.collection_class)
|
52
|
+
elsif Array(datatable.effective_resource&.actions).include?(:new)
|
53
|
+
effective_resource = datatable.effective_resource
|
54
|
+
klass = effective_resource.klass
|
55
|
+
else
|
56
|
+
return
|
57
|
+
end
|
58
|
+
|
59
|
+
# Will only work if permitted
|
60
|
+
render_resource_actions(klass, actions: { t('effective_datatables.new') => action }, effective_resource: effective_resource)
|
61
|
+
end
|
62
|
+
|
63
|
+
def datatable_label_tag(datatable, name, opts)
|
64
|
+
case opts[:as]
|
65
|
+
when :actions
|
66
|
+
content_tag(:span, t('effective_datatables.actions'), style: 'display: none;')
|
67
|
+
when :bulk_actions
|
68
|
+
content_tag(:span, t('effective_datatables.bulk_actions'), style: 'display: none;')
|
69
|
+
when :reorder
|
70
|
+
content_tag(:span, t('effective_datatables.reorder'), style: 'display: none;')
|
71
|
+
else
|
72
|
+
content_tag(:span, opts[:label].presence)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def datatable_search_tag(datatable, name, opts)
|
77
|
+
return datatable_new_resource_button(datatable, name, opts) if name == :_actions
|
78
|
+
|
79
|
+
return if opts[:search] == false
|
80
|
+
|
81
|
+
# Build the search
|
82
|
+
@_effective_datatables_form_builder || simple_form_for(:datatable_search, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| @_effective_datatables_form_builder = f }
|
83
|
+
form = @_effective_datatables_form_builder
|
84
|
+
|
34
85
|
include_blank = opts[:search].key?(:include_blank) ? opts[:search][:include_blank] : opts[:label]
|
35
86
|
pattern = opts[:search][:pattern]
|
36
87
|
placeholder = opts[:search][:placeholder] || ''
|
37
88
|
title = opts[:search][:title] || opts[:label]
|
38
89
|
wrapper_html = { class: 'datatable_search' }
|
39
90
|
|
91
|
+
collection = opts[:search].delete(:collection)
|
92
|
+
value = datatable.state[:search][name]
|
93
|
+
|
40
94
|
input_html = {
|
41
95
|
name: nil,
|
42
96
|
value: value,
|
@@ -83,7 +137,7 @@ module EffectiveDatatablesPrivateHelper
|
|
83
137
|
when :select, :boolean
|
84
138
|
form.input name, label: false, required: false, value: value,
|
85
139
|
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :select),
|
86
|
-
collection:
|
140
|
+
collection: collection,
|
87
141
|
selected: opts[:search][:value],
|
88
142
|
multiple: opts[:search][:multiple],
|
89
143
|
grouped: opts[:search][:grouped],
|
@@ -102,4 +156,76 @@ module EffectiveDatatablesPrivateHelper
|
|
102
156
|
end
|
103
157
|
end
|
104
158
|
|
105
|
-
|
159
|
+
def render_datatable_filters(datatable)
|
160
|
+
raise 'expected datatable to be present' unless datatable
|
161
|
+
|
162
|
+
datatable.view ||= self
|
163
|
+
return unless datatable._scopes.present? || datatable._filters.present?
|
164
|
+
|
165
|
+
if datatable._filters_form_required?
|
166
|
+
render partial: 'effective/datatables/filters', locals: { datatable: datatable }
|
167
|
+
else
|
168
|
+
render(partial: 'effective/datatables/filters', locals: { datatable: datatable }).gsub('<form', '<div').gsub('/form>', '/div>').html_safe
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
def datatable_filter_tag(form, datatable, name, opts)
|
174
|
+
as = opts[:as].to_s.chomp('_field').to_sym
|
175
|
+
value = datatable.state[:filter][name]
|
176
|
+
collection = opts[:collection]
|
177
|
+
input_html = opts[:input_html] || {}
|
178
|
+
|
179
|
+
binding.pry
|
180
|
+
|
181
|
+
form.input name,
|
182
|
+
value: value,
|
183
|
+
selected: value,
|
184
|
+
as: as,
|
185
|
+
collection: collection,
|
186
|
+
label: opts[:label],
|
187
|
+
required: input_html.delete(:required),
|
188
|
+
multiple: input_html.delete(:multiple),
|
189
|
+
include_blank: input_html.delete(:include_blank),
|
190
|
+
group_method: input_html.delete(:group_method),
|
191
|
+
group_label_method: input_html.delete(:group_label_method),
|
192
|
+
value_method: input_html.delete(:value_method),
|
193
|
+
label_method: input_html.delete(:label_method),
|
194
|
+
input_html: (({name: ''} unless datatable._filters_form_required?) || {}).merge(input_html),
|
195
|
+
input_js: ({ placeholder: ''} if as == :effective_select),
|
196
|
+
wrapper_html: {class: 'form-group-sm'}
|
197
|
+
end
|
198
|
+
|
199
|
+
def datatable_scope_tag(form, datatable, opts = {})
|
200
|
+
collection = datatable._scopes.map { |name, opts| [opts[:label], name] }
|
201
|
+
value = datatable.state[:scope]
|
202
|
+
|
203
|
+
form.input :scope, label: false, required: false, checked: value,
|
204
|
+
as: (defined?(EffectiveFormInputs) ? :effective_radio_buttons : :radio_buttons),
|
205
|
+
collection: collection,
|
206
|
+
buttons: true,
|
207
|
+
wrapper_html: {class: 'btn-group-sm'}
|
208
|
+
end
|
209
|
+
|
210
|
+
def render_datatable_charts(datatable)
|
211
|
+
raise 'expected datatable to be present' unless datatable
|
212
|
+
|
213
|
+
datatable.view ||= self
|
214
|
+
return unless datatable._charts.present?
|
215
|
+
|
216
|
+
datatable._charts.map { |name, _| render_datatable_chart(datatable, name) }.join.html_safe
|
217
|
+
end
|
218
|
+
|
219
|
+
def render_datatable_chart(datatable, name)
|
220
|
+
raise 'expected datatable to be present' unless datatable
|
221
|
+
|
222
|
+
datatable.view ||= self
|
223
|
+
return unless datatable._charts[name].present?
|
224
|
+
|
225
|
+
chart = datatable._charts[name]
|
226
|
+
chart_data = datatable.to_json[:charts][name][:data]
|
227
|
+
|
228
|
+
render partial: chart[:partial], locals: { datatable: datatable, chart: chart, chart_data: chart_data }
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|