effective_datatables 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +65 -6
- data/app/assets/javascripts/effective_datatables/initialize.js.coffee +2 -1
- data/app/controllers/effective/datatables_controller.rb +1 -1
- data/app/helpers/effective_datatables_helper.rb +16 -9
- data/app/models/effective/datatable.rb +48 -13
- data/app/views/effective/datatables/_datatable.html.haml +5 -1
- data/lib/effective_datatables/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42c5bd2f4e9f486d7aaf7b6eb9f50d518d454b54
|
4
|
+
data.tar.gz: b759ac1ff2af026ff64e514ee520d2e0a894ca53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70674bc43be1f4d30d4be2f97f73841bcf5300193a2e0968470669bd6902a015a8cf147e1aa91b799779a864fa8d331c165e16f9435111209efa8fa5f51d4aad
|
7
|
+
data.tar.gz: ee6b5e40da9ef3d41e70d951be314aabfd4cab55da491bfbb5f5197638ee9666dc06ba32218dd6c0ab6ef57292476a3f7ce61faaaee0ea920933b9dda77e5320
|
data/README.md
CHANGED
@@ -99,14 +99,10 @@ Here we just render the datatable:
|
|
99
99
|
|
100
100
|
```erb
|
101
101
|
<h1>All Posts</h1>
|
102
|
-
|
103
|
-
<% if @datatable.collection.length == 0 %>
|
104
|
-
<p>There are no posts.</p>
|
105
|
-
<% else %>
|
106
|
-
<%= render_datatable(@datatable) %>
|
107
|
-
<% end %>
|
102
|
+
<%= render_datatable(@datatable) %>
|
108
103
|
```
|
109
104
|
|
105
|
+
|
110
106
|
## How It Works
|
111
107
|
|
112
108
|
When the jQuery DataTable is first initialized on the front-end, it makes an AJAX request back to the server asking for data.
|
@@ -403,6 +399,69 @@ Valid options are `10, 25, 50, 100, 250, 1000, :all`
|
|
403
399
|
|
404
400
|
There are a few other ways to customize the behaviour of effective_datatables
|
405
401
|
|
402
|
+
### Display of an Empty Datatable
|
403
|
+
|
404
|
+
How an empty datatable (0 display records) is displayed depends on how `render_datatable` is called.
|
405
|
+
|
406
|
+
To render the full datatable with the default 'No data available in table' message:
|
407
|
+
|
408
|
+
```haml
|
409
|
+
= render_datatable(@datatable)
|
410
|
+
```
|
411
|
+
|
412
|
+
To skip rendering the datatable and just output a custom message:
|
413
|
+
|
414
|
+
```haml
|
415
|
+
= render_datatable(@datatable, 'There are no posts.')
|
416
|
+
```
|
417
|
+
|
418
|
+
or
|
419
|
+
|
420
|
+
```haml
|
421
|
+
= render_datatable(@datatable, :empty => 'There are no posts.')
|
422
|
+
```
|
423
|
+
|
424
|
+
To skip rendering the datatable and instead render given content:
|
425
|
+
|
426
|
+
```haml
|
427
|
+
= render_datatable(@datatable) do
|
428
|
+
%p There are no posts.
|
429
|
+
%p
|
430
|
+
Have a picture of a cat instead
|
431
|
+
= image_tag('cat.png')
|
432
|
+
```
|
433
|
+
|
434
|
+
### Checking for Empty collection
|
435
|
+
|
436
|
+
While the 'what to render when empty' situation is handled by the above syntax, you may still check whether the datatable has records to display by calling `@datatable.empty?` and `@datatable.present?`.
|
437
|
+
|
438
|
+
The gotcha with these methods is that the `@datatable.view` must first be assigned (which is done automatically by the `render_datatable` view method).
|
439
|
+
|
440
|
+
This implementation is a bit awkward but has significant performance tradeoffs.
|
441
|
+
|
442
|
+
To check for an empty datatable collection before it's rendered, you must manually assign a view:
|
443
|
+
|
444
|
+
```ruby
|
445
|
+
class PostsController < ApplicationController
|
446
|
+
def index
|
447
|
+
@datatable = Effective::Datatables::Posts.new()
|
448
|
+
@datatable.view = view_context # built in Rails controller method refering to the view
|
449
|
+
@datatable.empty?
|
450
|
+
end
|
451
|
+
end
|
452
|
+
```
|
453
|
+
|
454
|
+
or
|
455
|
+
|
456
|
+
```ruby
|
457
|
+
class PostsController < ApplicationController
|
458
|
+
def index
|
459
|
+
@datatable = Effective::Datatables::Posts.new()
|
460
|
+
@datatable.empty?(view_context)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
```
|
464
|
+
|
406
465
|
### Customize Filter Behaviour
|
407
466
|
|
408
467
|
This gem does its best to provide "just works" filtering of both raw SQL (table_column) and processed results (array_column) out-of-the-box.
|
@@ -13,6 +13,7 @@ initializeDataTables = ->
|
|
13
13
|
bProcessing: true
|
14
14
|
bSaveState: true
|
15
15
|
bAutoWidth: false
|
16
|
+
deferLoading: datatable.data('total-entries')
|
16
17
|
deferRender: true
|
17
18
|
order: datatable.data('default-order')
|
18
19
|
sAjaxSource: datatable.data('source')
|
@@ -27,7 +28,7 @@ initializeDataTables = ->
|
|
27
28
|
# If this is the very first request to the server we have to manually set any selected filter options here
|
28
29
|
# So that we can skip an fnFilter call in the dataTables.columnFilter that results in a double AJAX call
|
29
30
|
((sEcho = data; break) if data.name == 'sEcho') for data in aoData
|
30
|
-
if sEcho && sEcho.value ==
|
31
|
+
if sEcho && sEcho.value == 2
|
31
32
|
$.each (datatable.data('filter') || []), (index, filter) ->
|
32
33
|
if(filter.selected)
|
33
34
|
sSearch = undefined
|
@@ -4,7 +4,7 @@ module Effective
|
|
4
4
|
|
5
5
|
def show
|
6
6
|
@datatable = Effective::Datatable.find(params[:id], params[:attributes])
|
7
|
-
@datatable.view = view_context if
|
7
|
+
@datatable.view = view_context if !@datatable.nil?
|
8
8
|
|
9
9
|
EffectiveDatatables.authorized?(self, :index, @datatable.try(:collection_class) || Effective::Datatable)
|
10
10
|
|
@@ -1,10 +1,23 @@
|
|
1
1
|
module EffectiveDatatablesHelper
|
2
|
-
def render_datatable(datatable, opts = {})
|
2
|
+
def render_datatable(datatable, opts = {}, &block)
|
3
3
|
datatable.view = self
|
4
|
-
|
4
|
+
|
5
|
+
locals = {:style => :full, :filterable => true, :sortable => true, :table_class => 'table-bordered table-striped'}
|
6
|
+
locals = locals.merge(opts) if opts.kind_of?(Hash)
|
5
7
|
locals[:table_class] = 'sorting-hidden ' + locals[:table_class].to_s if locals[:sortable] == false
|
6
8
|
|
7
|
-
|
9
|
+
# Do we have to look at empty? behaviour
|
10
|
+
if (block_given? || opts.kind_of?(String) || (opts.kind_of?(Hash) && opts[:empty].present?)) && datatable.empty?
|
11
|
+
if block_given?
|
12
|
+
yield; nil
|
13
|
+
elsif opts.kind_of?(String)
|
14
|
+
opts
|
15
|
+
elsif opts.kind_of?(Hash) && opts[:empty].present?
|
16
|
+
opts[:empty]
|
17
|
+
end
|
18
|
+
else
|
19
|
+
render :partial => 'effective/datatables/datatable', :locals => locals.merge(:datatable => datatable)
|
20
|
+
end
|
8
21
|
end
|
9
22
|
|
10
23
|
def render_simple_datatable(datatable, opts = {})
|
@@ -58,12 +71,6 @@ module EffectiveDatatablesHelper
|
|
58
71
|
].to_json()
|
59
72
|
end
|
60
73
|
|
61
|
-
def datatable_default_entries(datatable)
|
62
|
-
default_entries = (datatable.default_entries.presence || EffectiveDatatables.default_entries)
|
63
|
-
default_entries = -1 if default_entries.to_s.downcase == 'all'
|
64
|
-
[10, 25, 50, 100, 250, 1000, -1].include?(default_entries) ? default_entries : 25
|
65
|
-
end
|
66
|
-
|
67
74
|
def datatable_widths(datatable)
|
68
75
|
datatable.table_columns.values.map { |options| {'sWidth' => options[:width]} if options[:width] }.to_json()
|
69
76
|
end
|
@@ -44,7 +44,6 @@ module Effective
|
|
44
44
|
def default_entries(entries)
|
45
45
|
@default_entries = entries
|
46
46
|
end
|
47
|
-
|
48
47
|
end
|
49
48
|
|
50
49
|
def initialize(*args)
|
@@ -86,8 +85,10 @@ module Effective
|
|
86
85
|
end.each_with_index { |(_, col), index| col[:index] = index }
|
87
86
|
end
|
88
87
|
|
89
|
-
def to_json
|
90
|
-
|
88
|
+
def to_json
|
89
|
+
raise 'Effective::Datatable to_json called with a nil view. Please call render_datatable(@datatable) or @datatable.view = view before this method' unless view.present?
|
90
|
+
|
91
|
+
@json ||= {
|
91
92
|
:sEcho => params[:sEcho].to_i,
|
92
93
|
:aaData => table_data || [],
|
93
94
|
:iTotalRecords => (
|
@@ -105,14 +106,35 @@ module Effective
|
|
105
106
|
}
|
106
107
|
end
|
107
108
|
|
108
|
-
|
109
|
+
def present?(view = nil)
|
110
|
+
self.view = view unless view.nil?
|
111
|
+
to_json[:iTotalDisplayRecords] > 0
|
112
|
+
end
|
109
113
|
|
114
|
+
def empty?(view = nil)
|
115
|
+
self.view = view unless view.nil?
|
116
|
+
to_json[:iTotalDisplayRecords] == 0
|
117
|
+
end
|
118
|
+
|
119
|
+
# Wish these were protected
|
110
120
|
def order_column_index
|
111
|
-
params[:iSortCol_0].
|
121
|
+
if params[:iSortCol_0].present?
|
122
|
+
params[:iSortCol_0].to_i
|
123
|
+
elsif default_order.present?
|
124
|
+
table_columns[default_order.keys.first].fetch(:index, 0)
|
125
|
+
else
|
126
|
+
0
|
127
|
+
end
|
112
128
|
end
|
113
129
|
|
114
130
|
def order_direction
|
115
|
-
params[:sSortDir_0].
|
131
|
+
if params[:sSortDir_0].present?
|
132
|
+
params[:sSortDir_0].try(:downcase) == 'desc' ? 'DESC' : 'ASC'
|
133
|
+
elsif default_order.present?
|
134
|
+
default_order.values.first.to_s.downcase == 'desc' ? 'DESC' : 'ASC'
|
135
|
+
else
|
136
|
+
'ASC'
|
137
|
+
end
|
116
138
|
end
|
117
139
|
|
118
140
|
def default_order
|
@@ -120,14 +142,27 @@ module Effective
|
|
120
142
|
end
|
121
143
|
|
122
144
|
def default_entries
|
123
|
-
|
145
|
+
@default_entries ||= begin
|
146
|
+
entries = (self.class.instance_variable_get(:@default_entries).presence || EffectiveDatatables.default_entries)
|
147
|
+
entries = -1 if entries.to_s.downcase == 'all'
|
148
|
+
[10, 25, 50, 100, 250, 1000, -1].include?(entries) ? entries : 25
|
149
|
+
end
|
124
150
|
end
|
125
151
|
|
126
152
|
def search_terms
|
127
153
|
@search_terms ||= HashWithIndifferentAccess.new().tap do |terms|
|
128
|
-
|
129
|
-
|
130
|
-
|
154
|
+
if params[:sEcho].present?
|
155
|
+
table_columns.keys.each_with_index do |col, x|
|
156
|
+
unless (params["sVisible_#{x}"] == 'false' && table_columns[col][:filter][:when_hidden] != true)
|
157
|
+
terms[col] = params["sSearch_#{x}"] if params["sSearch_#{x}"].present?
|
158
|
+
end
|
159
|
+
end
|
160
|
+
else
|
161
|
+
# We are in the initial render and have to apply default search terms only
|
162
|
+
table_columns.each do |name, values|
|
163
|
+
if (values[:filter][:selected].present?) && (values[:visible] != false || values[:filter][:when_hidden] == true)
|
164
|
+
terms[name] = values[:filter][:selected]
|
165
|
+
end
|
131
166
|
end
|
132
167
|
end
|
133
168
|
end
|
@@ -150,7 +185,7 @@ module Effective
|
|
150
185
|
elsif length > 0
|
151
186
|
length
|
152
187
|
else
|
153
|
-
|
188
|
+
default_entries
|
154
189
|
end
|
155
190
|
end
|
156
191
|
|
@@ -188,13 +223,13 @@ module Effective
|
|
188
223
|
col = collection
|
189
224
|
|
190
225
|
if active_record_collection?
|
191
|
-
self.total_records = (collection_class.connection.execute("SELECT COUNT(*) FROM (#{col.to_sql}) AS
|
226
|
+
self.total_records = (collection_class.connection.execute("SELECT COUNT(*) FROM (#{col.to_sql}) AS datatables_total_count").first['count'] rescue 1)
|
192
227
|
|
193
228
|
col = table_tool.order(col)
|
194
229
|
col = table_tool.search(col)
|
195
230
|
|
196
231
|
if table_tool.search_terms.present? && array_tool.search_terms.blank?
|
197
|
-
self.display_records = (collection_class.connection.execute("SELECT COUNT(*) FROM (#{col.to_sql}) AS
|
232
|
+
self.display_records = (collection_class.connection.execute("SELECT COUNT(*) FROM (#{col.to_sql}) AS datatables_filtered_count").first['count'] rescue 1)
|
198
233
|
end
|
199
234
|
else
|
200
235
|
self.total_records = col.size
|
@@ -1,4 +1,4 @@
|
|
1
|
-
%table.effective-datatable{:id => "#{datatable.to_param}-table", :class => ('table ' + table_class.to_s), :data => {'effective-datatables-table' => style, 'source' => effective_datatables.datatable_path(datatable, {:format => 'json'}.merge(:attributes => datatable.attributes)), 'filter' => datatable_filter(datatable, filterable), 'non-sortable' => datatable_non_sortable(datatable, sortable), 'non-visible' => datatable_non_visible(datatable), 'widths' => datatable_widths(datatable), 'default-order' => datatable_default_order(datatable), 'default-entries' =>
|
1
|
+
%table.effective-datatable{:id => "#{datatable.to_param}-table", :class => ('table ' + table_class.to_s), :data => {'effective-datatables-table' => style, 'source' => effective_datatables.datatable_path(datatable, {:format => 'json'}.merge(:attributes => datatable.attributes)), 'filter' => datatable_filter(datatable, filterable), 'non-sortable' => datatable_non_sortable(datatable, sortable), 'non-visible' => datatable_non_visible(datatable), 'widths' => datatable_widths(datatable), 'default-order' => datatable_default_order(datatable), 'default-entries' => datatable.default_entries, 'total-entries' => (datatable.to_json[:iTotalRecords] || false), 'column-classes' => datatable_column_classes(datatable)}}
|
2
2
|
%thead
|
3
3
|
- max_depth = datatable.table_columns.map { |_, opts| opts[:th][:depth].to_i rescue 0 }.max
|
4
4
|
- [*0..max_depth].each do |depth|
|
@@ -9,3 +9,7 @@
|
|
9
9
|
- (opts[:append_th] || []).each do |faux_col|
|
10
10
|
%th{(faux_col[:th] || {}).merge({:title => faux_col[:label]})}= faux_col[:label]
|
11
11
|
%tbody
|
12
|
+
- (datatable.to_json[:aaData] || []).each do |row|
|
13
|
+
%tr
|
14
|
+
- row.each do |col|
|
15
|
+
%td= col.to_s.html_safe
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_datatables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
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: 2015-03-
|
11
|
+
date: 2015-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|