effective_datatables 1.2.5 → 1.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 087d65c39d2b88c60fcc041b5f7a564bc61bded7
4
- data.tar.gz: 611af4b47aaa06ccb61d59b5d8cd4bcb56363d91
3
+ metadata.gz: 42c5bd2f4e9f486d7aaf7b6eb9f50d518d454b54
4
+ data.tar.gz: b759ac1ff2af026ff64e514ee520d2e0a894ca53
5
5
  SHA512:
6
- metadata.gz: 6ddaca87e620c93d477081bd48fc4e6ba8029fef349ef3042d1b4b4dae736d6603822366d9d7f0741f0ecb5280e91833466ed2fd9a53b520d79b4e5de066d08c
7
- data.tar.gz: e2217a2fd7c3b191bbf755a55f46b5ac85ac6ec44d67a6465302590710982660f3ab4f4a3d56661c4f47864c0d1023e49cd3073cce75c59795e345a9df26e840
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 == 1
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 @datatable.present?
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
- locals = {:style => :full, :filterable => true, :sortable => true, :table_class => 'table-bordered table-striped'}.merge(opts)
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
- render :partial => 'effective/datatables/datatable', :locals => locals.merge(:datatable => datatable)
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(options = {})
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
- # Wish these were protected
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].to_i
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].try(:downcase) == 'desc' ? 'DESC' : 'ASC'
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
- self.class.instance_variable_get(:@default_entries)
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
- table_columns.keys.each_with_index do |col, x|
129
- unless (params["sVisible_#{x}"] == 'false' && table_columns[col][:filter][:when_hidden] != true)
130
- terms[col] = params["sSearch_#{x}"] if params["sSearch_#{x}"].present?
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
- 10
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 datatables_count").first['count'] rescue 1)
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 datatables_count").first['count'] rescue 1)
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' => datatable_default_entries(datatable), 'column-classes' => datatable_column_classes(datatable)}}
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
@@ -1,3 +1,3 @@
1
1
  module EffectiveDatatables
2
- VERSION = '1.2.5'.freeze
2
+ VERSION = '1.3.0'.freeze
3
3
  end
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.2.5
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-09 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails