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