effective_datatables 4.3.4 → 4.3.5
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 +19 -1
- data/app/assets/javascripts/dataTables/buttons/buttons.bootstrap4.js +1 -0
- data/app/assets/javascripts/dataTables/buttons/buttons.colVis.js +12 -2
- data/app/assets/javascripts/dataTables/buttons/buttons.html5.js +58 -6
- data/app/assets/javascripts/dataTables/buttons/buttons.print.js +16 -5
- data/app/assets/javascripts/dataTables/buttons/dataTables.buttons.js +26 -10
- data/app/assets/javascripts/dataTables/rowReorder/dataTables.rowReorder.js +818 -0
- data/app/assets/javascripts/dataTables/rowReorder/rowReorder.bootstrap4.js +38 -0
- data/app/assets/javascripts/effective_datatables.js +3 -10
- data/app/assets/javascripts/effective_datatables/flash.js.coffee +20 -0
- data/app/assets/javascripts/effective_datatables/initialize.js.coffee +12 -1
- data/app/assets/javascripts/effective_datatables/overrides.js.coffee +0 -24
- data/app/assets/javascripts/effective_datatables/reorder.js.coffee +37 -0
- data/app/assets/stylesheets/dataTables/buttons/buttons.bootstrap4.css +6 -0
- data/app/assets/stylesheets/dataTables/rowReorder/rowReorder.bootstrap4.css +22 -0
- data/app/assets/stylesheets/effective_datatables.scss +1 -0
- data/app/assets/stylesheets/effective_datatables/_overrides.scss +15 -2
- data/app/controllers/effective/datatables_controller.rb +25 -0
- data/app/helpers/effective_datatables_helper.rb +3 -1
- data/app/helpers/effective_datatables_private_helper.rb +28 -4
- data/app/models/effective/datatable.rb +23 -3
- data/app/models/effective/effective_datatable/dsl.rb +1 -1
- data/app/models/effective/effective_datatable/dsl/datatable.rb +65 -26
- data/app/models/effective/effective_datatable/format.rb +7 -4
- data/app/models/effective/effective_datatable/resource.rb +0 -2
- data/app/models/effective/effective_datatable/state.rb +15 -8
- data/app/views/effective/datatables/_reorder_column.html.haml +5 -0
- data/config/routes.rb +1 -0
- data/lib/effective_datatables/version.rb +1 -1
- metadata +8 -2
@@ -0,0 +1,38 @@
|
|
1
|
+
/*! Bootstrap 4 styling wrapper for RowReorder
|
2
|
+
* ©2018 SpryMedia Ltd - datatables.net/license
|
3
|
+
*/
|
4
|
+
|
5
|
+
(function( factory ){
|
6
|
+
if ( typeof define === 'function' && define.amd ) {
|
7
|
+
// AMD
|
8
|
+
define( ['jquery', 'datatables.net-bs4', 'datatables.net-rowreorder'], function ( $ ) {
|
9
|
+
return factory( $, window, document );
|
10
|
+
} );
|
11
|
+
}
|
12
|
+
else if ( typeof exports === 'object' ) {
|
13
|
+
// CommonJS
|
14
|
+
module.exports = function (root, $) {
|
15
|
+
if ( ! root ) {
|
16
|
+
root = window;
|
17
|
+
}
|
18
|
+
|
19
|
+
if ( ! $ || ! $.fn.dataTable ) {
|
20
|
+
$ = require('datatables.net-bs4')(root, $).$;
|
21
|
+
}
|
22
|
+
|
23
|
+
if ( ! $.fn.dataTable.RowReorder ) {
|
24
|
+
require('datatables.net-rowreorder')(root, $);
|
25
|
+
}
|
26
|
+
|
27
|
+
return factory( $, root, root.document );
|
28
|
+
};
|
29
|
+
}
|
30
|
+
else {
|
31
|
+
// Browser
|
32
|
+
factory( jQuery, window, document );
|
33
|
+
}
|
34
|
+
}(function( $, window, document, undefined ) {
|
35
|
+
|
36
|
+
return $.fn.dataTable;
|
37
|
+
|
38
|
+
}));
|
@@ -11,14 +11,7 @@
|
|
11
11
|
//= require dataTables/buttons/buttons.print
|
12
12
|
//= require dataTables/responsive/dataTables.responsive
|
13
13
|
//= require dataTables/responsive/responsive.bootstrap4
|
14
|
+
//= require dataTables/rowReorder/dataTables.rowReorder
|
15
|
+
//= require dataTables/rowReorder/rowReorder.bootstrap4
|
14
16
|
|
15
|
-
//=
|
16
|
-
//= require effective_datatables/events
|
17
|
-
//= require effective_datatables/filters
|
18
|
-
//= require effective_datatables/inline_crud
|
19
|
-
//= require effective_datatables/reset
|
20
|
-
//= require effective_datatables/responsive
|
21
|
-
//= require effective_datatables/overrides
|
22
|
-
|
23
|
-
//= require effective_datatables/charts
|
24
|
-
//= require effective_datatables/initialize
|
17
|
+
//= require_tree ./effective_datatables
|
@@ -0,0 +1,20 @@
|
|
1
|
+
flash = (message) ->
|
2
|
+
@context[0].oFeatures.bProcessing = false
|
3
|
+
|
4
|
+
message ||= 'Processing...'
|
5
|
+
|
6
|
+
$processing = $(@table().node()).siblings('.dataTables_processing')
|
7
|
+
$processing.html(message).show()
|
8
|
+
|
9
|
+
timeout = $processing.data('timeout')
|
10
|
+
clearTimeout(timeout) if timeout
|
11
|
+
|
12
|
+
$processing.html(message).data('timeout', setTimeout( =>
|
13
|
+
$processing.html('Processing...').hide()
|
14
|
+
@context[0].oFeatures.bProcessing = true
|
15
|
+
, 1500)
|
16
|
+
)
|
17
|
+
|
18
|
+
return @
|
19
|
+
|
20
|
+
$.fn.DataTable.Api.register('flash()', flash);
|
@@ -4,6 +4,7 @@ initializeDataTables = ->
|
|
4
4
|
options = datatable.data('options') || {}
|
5
5
|
buttons_export_columns = options['buttons_export_columns'] || ':not(.col-actions)'
|
6
6
|
simple = ('' + datatable.data('simple') == 'true')
|
7
|
+
reorder = datatable.data('reorder')
|
7
8
|
|
8
9
|
if options['buttons'] == false
|
9
10
|
options['buttons'] = []
|
@@ -16,7 +17,8 @@ initializeDataTables = ->
|
|
16
17
|
extend: 'colvis',
|
17
18
|
text: 'Show / Hide',
|
18
19
|
postfixButtons: [
|
19
|
-
{ extend: 'colvisGroup', text: 'Show all', show: ':hidden'},
|
20
|
+
{ extend: 'colvisGroup', text: 'Show all', show: ':hidden', className: 'buttons-colvisGroup-first'},
|
21
|
+
{ extend: 'colvisGroup', text: 'Show none', hide: ':visible'}
|
20
22
|
{ extend: 'colvisRestore', text: 'Show default'}
|
21
23
|
]
|
22
24
|
},
|
@@ -102,6 +104,9 @@ initializeDataTables = ->
|
|
102
104
|
if $table.data('reset')
|
103
105
|
$buttons.prepend($table.data('reset'))
|
104
106
|
|
107
|
+
if $table.data('reorder')
|
108
|
+
$buttons.prepend($table.data('reorder'))
|
109
|
+
|
105
110
|
if $table.data('bulk-actions')
|
106
111
|
$buttons.prepend($table.data('bulk-actions'))
|
107
112
|
|
@@ -160,6 +165,9 @@ initializeDataTables = ->
|
|
160
165
|
init_options['dom'] = "<'row'<'col-sm-12'tr>>" # Just show the table
|
161
166
|
datatable.addClass('simple')
|
162
167
|
|
168
|
+
if reorder
|
169
|
+
init_options['rowReorder'] = { selector: 'td.col-_reorder', snapX: true, dataSrc: datatable.data('reorder-index') }
|
170
|
+
|
163
171
|
# Let's actually initialize the table now
|
164
172
|
table = datatable.dataTable(jQuery.extend(init_options, options))
|
165
173
|
|
@@ -169,6 +177,9 @@ initializeDataTables = ->
|
|
169
177
|
# Apply EffectiveFormInputs to the Show x per page dropdown
|
170
178
|
try table.closest('.dataTables_wrapper').find('.dataTables_length select').removeAttr('name').select2(minimumResultsForSearch: 100)
|
171
179
|
|
180
|
+
if reorder
|
181
|
+
table.DataTable().on('row-reorder', (event, diff, edit) -> $(event.target).DataTable().reorder(event, diff, edit))
|
182
|
+
|
172
183
|
table.addClass('initialized')
|
173
184
|
|
174
185
|
destroyDataTables = ->
|
@@ -5,27 +5,3 @@ $.extend(true, $.fn.dataTable.Buttons.defaults, {
|
|
5
5
|
}
|
6
6
|
}
|
7
7
|
});
|
8
|
-
|
9
|
-
# DataTable is the API
|
10
|
-
# dataTable is the object fnStuff
|
11
|
-
|
12
|
-
flash = (message) ->
|
13
|
-
@context[0].oFeatures.bProcessing = false
|
14
|
-
|
15
|
-
message ||= 'Processing...'
|
16
|
-
|
17
|
-
$processing = $(@table().node()).siblings('.dataTables_processing')
|
18
|
-
$processing.html(message).show()
|
19
|
-
|
20
|
-
timeout = $processing.data('timeout')
|
21
|
-
clearTimeout(timeout) if timeout
|
22
|
-
|
23
|
-
$processing.html(message).data('timeout', setTimeout( =>
|
24
|
-
$processing.html('Processing...').hide()
|
25
|
-
@context[0].oFeatures.bProcessing = true
|
26
|
-
, 1500)
|
27
|
-
)
|
28
|
-
|
29
|
-
return @
|
30
|
-
|
31
|
-
$.fn.DataTable.Api.register('flash()', flash);
|
@@ -0,0 +1,37 @@
|
|
1
|
+
reorder = (event, diff, edit) ->
|
2
|
+
change = diff.find (obj) -> obj.node == edit.triggerRow.node()
|
3
|
+
return unless change?
|
4
|
+
|
5
|
+
oldNode = $("<div>#{change.oldData}</div>").find('input[data-reorder-resource]')
|
6
|
+
newNode = $("<div>#{change.newData}</div>").find('input[data-reorder-resource]')
|
7
|
+
return unless oldNode? && newNode?
|
8
|
+
|
9
|
+
url = @context[0].ajax.url.replace('.json', '/reorder.json')
|
10
|
+
data = {'reorder[id]': oldNode.data('reorder-resource'), 'reorder[old]': oldNode.val(), 'reorder[new]': newNode.val()}
|
11
|
+
|
12
|
+
@context[0].rowreorder.c.enable = false
|
13
|
+
|
14
|
+
$.ajax(
|
15
|
+
method: 'post',
|
16
|
+
url: url,
|
17
|
+
data: data,
|
18
|
+
async: false
|
19
|
+
).fail((response, text, status) =>
|
20
|
+
$(event.target).closest('table').DataTable().flash(status)
|
21
|
+
).always((response) =>
|
22
|
+
@context[0].rowreorder.c.enable = true
|
23
|
+
)
|
24
|
+
|
25
|
+
$.fn.DataTable.Api.register('reorder()', reorder);
|
26
|
+
|
27
|
+
$(document).on 'click', '.dataTables_wrapper a.buttons-reorder', (event) ->
|
28
|
+
event.preventDefault() # prevent the click
|
29
|
+
|
30
|
+
$link = $(event.currentTarget)
|
31
|
+
$table = $link.closest('.dataTables_wrapper').find('table.dataTable').first()
|
32
|
+
|
33
|
+
column = $table.DataTable().column('.col-_reorder')
|
34
|
+
return unless column.length > 0
|
35
|
+
|
36
|
+
column.visible(!column.visible())
|
37
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
table.dt-rowReorder-float {
|
2
|
+
position: absolute !important;
|
3
|
+
opacity: 0.8;
|
4
|
+
table-layout: fixed;
|
5
|
+
outline: 2px solid #0275d8;
|
6
|
+
outline-offset: -2px;
|
7
|
+
z-index: 2001;
|
8
|
+
}
|
9
|
+
|
10
|
+
tr.dt-rowReorder-moving {
|
11
|
+
outline: 2px solid #888;
|
12
|
+
outline-offset: -2px;
|
13
|
+
}
|
14
|
+
|
15
|
+
body.dt-rowReorder-noOverflow {
|
16
|
+
overflow-x: hidden;
|
17
|
+
}
|
18
|
+
|
19
|
+
table.dataTable td.reorder {
|
20
|
+
text-align: center;
|
21
|
+
cursor: move;
|
22
|
+
}
|
@@ -52,7 +52,6 @@ table.dataTable > thead {
|
|
52
52
|
}
|
53
53
|
|
54
54
|
table.dataTable > thead th {
|
55
|
-
vertical-align: top;
|
56
55
|
background-repeat: no-repeat;
|
57
56
|
|
58
57
|
> span { padding-right: 1rem; }
|
@@ -95,6 +94,13 @@ table.dataTable > tbody > tr.child {
|
|
95
94
|
.btn { font-size: 0.75rem; }
|
96
95
|
}
|
97
96
|
|
97
|
+
div.dt-button-collection-title { padding: 0px; }
|
98
|
+
|
99
|
+
.dt-button.buttons-colvisGroup-first {
|
100
|
+
padding-top: 0.5rem;
|
101
|
+
border-top: 1px solid #dee2e6;
|
102
|
+
}
|
103
|
+
|
98
104
|
// Search bar
|
99
105
|
table.dataTable > thead {
|
100
106
|
tr th {
|
@@ -113,10 +119,13 @@ table.dataTable > thead {
|
|
113
119
|
cursor: pointer;
|
114
120
|
}
|
115
121
|
}
|
116
|
-
|
117
122
|
}
|
118
123
|
}
|
119
124
|
|
125
|
+
table.dataTable.collapsed {
|
126
|
+
th.col-bulk_actions:first-child { div { margin-left: 18px; } }
|
127
|
+
}
|
128
|
+
|
120
129
|
// Processing div
|
121
130
|
div.dataTables_wrapper div.dataTables_processing {
|
122
131
|
position: absolute;
|
@@ -198,6 +207,10 @@ table.dataTable {
|
|
198
207
|
text-align: right;
|
199
208
|
}
|
200
209
|
|
210
|
+
td.col-reorder {
|
211
|
+
cursor: move;
|
212
|
+
}
|
213
|
+
|
201
214
|
td.col-resource_item { word-break: keep-all; }
|
202
215
|
|
203
216
|
td {
|
@@ -18,7 +18,32 @@ module Effective
|
|
18
18
|
ExceptionNotifier.notify_exception(e) if defined?(ExceptionNotifier)
|
19
19
|
raise e if Rails.env.development?
|
20
20
|
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def reorder
|
24
|
+
@datatable = EffectiveDatatables.find(params[:id])
|
25
|
+
@datatable.view = view_context
|
26
|
+
|
27
|
+
@resource = @datatable.collection.find(params[:reorder][:id])
|
28
|
+
EffectiveDatatables.authorize!(self, :update, @resource)
|
29
|
+
|
30
|
+
attribute = @datatable.columns[:_reorder][:reorder]
|
31
|
+
old_index = params[:reorder][:old].to_i
|
32
|
+
new_index = params[:reorder][:new].to_i
|
33
|
+
|
34
|
+
@resource.class.transaction do
|
35
|
+
if new_index > old_index
|
36
|
+
@datatable.collection.where("#{attribute} > ? AND #{attribute} <= ?", old_index, new_index).update_all("#{attribute} = #{attribute} - 1")
|
37
|
+
@resource.update_column(attribute, new_index)
|
38
|
+
end
|
39
|
+
|
40
|
+
if old_index > new_index
|
41
|
+
@datatable.collection.where("#{attribute} >= ? AND #{attribute} < ?", new_index, old_index).update_all("#{attribute} = #{attribute} + 1")
|
42
|
+
@resource.update_column(attribute, new_index)
|
43
|
+
end
|
44
|
+
end
|
21
45
|
|
46
|
+
render status: :ok, body: :ok
|
22
47
|
end
|
23
48
|
|
24
49
|
private
|
@@ -26,12 +26,14 @@ module EffectiveDatatablesHelper
|
|
26
26
|
'columns' => datatable_columns(datatable),
|
27
27
|
'cookie' => datatable.cookie_key,
|
28
28
|
'display-length' => datatable.display_length,
|
29
|
-
'display-order' =>
|
29
|
+
'display-order' => datatable_display_order(datatable),
|
30
30
|
'display-records' => datatable.to_json[:recordsFiltered],
|
31
31
|
'display-start' => datatable.display_start,
|
32
32
|
'inline' => datatable.inline?.to_s,
|
33
33
|
'options' => (input_js || {}).to_json.html_safe,
|
34
34
|
'reset' => datatable_reset(datatable),
|
35
|
+
'reorder' => datatable_reorder(datatable),
|
36
|
+
'reorder-index' => (datatable.columns[:_reorder][:index] if datatable.reorder?).to_s,
|
35
37
|
'simple' => datatable.simple?.to_s,
|
36
38
|
'spinner' => icon('spinner'), # effective_bootstrap
|
37
39
|
'source' => effective_datatables.datatable_path(datatable, {format: 'json'}),
|
@@ -3,16 +3,18 @@ module EffectiveDatatablesPrivateHelper
|
|
3
3
|
|
4
4
|
# https://datatables.net/reference/option/columns
|
5
5
|
def datatable_columns(datatable)
|
6
|
+
sortable = datatable.sortable?
|
7
|
+
|
6
8
|
datatable.columns.map do |name, opts|
|
7
9
|
{
|
8
|
-
name: name,
|
9
|
-
title: content_tag(:span, opts[:label].presence),
|
10
10
|
className: opts[:col_class],
|
11
|
+
name: name,
|
11
12
|
responsivePriority: opts[:responsive],
|
12
13
|
search: datatable.state[:search][name],
|
13
14
|
searchHtml: datatable_search_tag(datatable, name, opts),
|
14
|
-
sortable: (opts[:sort] &&
|
15
|
-
|
15
|
+
sortable: (opts[:sort] && sortable),
|
16
|
+
title: datatable_label_tag(datatable, name, opts),
|
17
|
+
visible: datatable.state[:visible][name]
|
16
18
|
}
|
17
19
|
end.to_json.html_safe
|
18
20
|
end
|
@@ -23,10 +25,19 @@ module EffectiveDatatablesPrivateHelper
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
def datatable_display_order(datatable)
|
29
|
+
(datatable.sortable? ? [datatable.order_index, datatable.order_direction] : false).to_json.html_safe
|
30
|
+
end
|
31
|
+
|
26
32
|
def datatable_reset(datatable)
|
27
33
|
link_to(content_tag(:span, 'Reset'), '#', class: 'btn btn-link btn-sm buttons-reset-search')
|
28
34
|
end
|
29
35
|
|
36
|
+
def datatable_reorder(datatable)
|
37
|
+
return false unless datatable.reorder?
|
38
|
+
link_to(content_tag(:span, 'Reorder'), '#', class: 'btn btn-link btn-sm buttons-reorder')
|
39
|
+
end
|
40
|
+
|
30
41
|
def datatable_new_resource_button(datatable, name, column)
|
31
42
|
if column[:inline] && column[:actions][:new] != false
|
32
43
|
actions = {'New' => { action: :new, class: 'btn btn-outline-primary', 'data-remote': true } }
|
@@ -34,6 +45,19 @@ module EffectiveDatatablesPrivateHelper
|
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
48
|
+
def datatable_label_tag(datatable, name, opts)
|
49
|
+
case opts[:as]
|
50
|
+
when :actions
|
51
|
+
content_tag(:span, 'Actions', style: 'display: none;')
|
52
|
+
when :bulk_actions
|
53
|
+
content_tag(:span, 'Bulk Actions', style: 'display: none;')
|
54
|
+
when :reorder
|
55
|
+
content_tag(:span, 'Reorder', style: 'display: none;')
|
56
|
+
else
|
57
|
+
content_tag(:span, opts[:label].presence)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
37
61
|
def datatable_search_tag(datatable, name, opts)
|
38
62
|
return datatable_new_resource_button(datatable, name, opts) if name == :_actions
|
39
63
|
|
@@ -63,12 +63,14 @@ module Effective
|
|
63
63
|
load_filters!
|
64
64
|
load_state!
|
65
65
|
|
66
|
+
# Bulk actions called first so it can add the bulk_actions_col first
|
67
|
+
initialize_bulk_actions if respond_to?(:initialize_bulk_actions)
|
68
|
+
|
66
69
|
# Now we initialize all the columns. columns knows about attributes and filters and scope
|
67
70
|
initialize_datatable if respond_to?(:initialize_datatable)
|
68
71
|
load_columns!
|
69
72
|
|
70
73
|
# Execute any additional DSL methods
|
71
|
-
initialize_bulk_actions if respond_to?(:initialize_bulk_actions)
|
72
74
|
initialize_charts if respond_to?(:initialize_charts)
|
73
75
|
|
74
76
|
# Load the collection. This is the first time def collection is called on the Datatable itself
|
@@ -77,10 +79,13 @@ module Effective
|
|
77
79
|
|
78
80
|
# Figure out the class, and if it's activerecord, do all the resource discovery on it
|
79
81
|
load_resource!
|
80
|
-
|
81
|
-
# If attributes match a belongs_to column, scope the collection and remove the column
|
82
|
+
load_resource_search!
|
82
83
|
apply_belongs_to_attributes!
|
83
84
|
|
85
|
+
# Check everything is okay
|
86
|
+
validate_datatable!
|
87
|
+
|
88
|
+
# Save for next time
|
84
89
|
save_cookie!
|
85
90
|
end
|
86
91
|
|
@@ -129,6 +134,14 @@ module Effective
|
|
129
134
|
attributes[:inline] == true
|
130
135
|
end
|
131
136
|
|
137
|
+
def reorder?
|
138
|
+
columns.key?(:_reorder)
|
139
|
+
end
|
140
|
+
|
141
|
+
def sortable?
|
142
|
+
!simple? && !reorder?
|
143
|
+
end
|
144
|
+
|
132
145
|
# Whether the filters must be rendered as a <form> or we can keep the normal <div> behaviour
|
133
146
|
def _filters_form_required?
|
134
147
|
_form[:verb].present?
|
@@ -164,5 +177,12 @@ module Effective
|
|
164
177
|
@value_tool ||= DatatableValueTool.new(self)
|
165
178
|
end
|
166
179
|
|
180
|
+
def validate_datatable!
|
181
|
+
if reorder?
|
182
|
+
raise 'cannot use reorder with an Array collection' if array_collection?
|
183
|
+
raise 'cannot use reorder with a non-Integer column' if resource.sql_type(columns[:_reorder][:reorder]) != :integer
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
167
187
|
end
|
168
188
|
end
|