effective_datatables 2.12.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +632 -512
  3. data/app/assets/javascripts/dataTables/buttons/buttons.html5.js +176 -177
  4. data/app/assets/javascripts/dataTables/buttons/buttons.print.js +2 -0
  5. data/app/assets/javascripts/dataTables/buttons/dataTables.buttons.js +14 -14
  6. data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +1 -1
  7. data/app/assets/javascripts/dataTables/jquery.dataTables.js +246 -217
  8. data/app/assets/javascripts/effective_datatables.js +2 -3
  9. data/app/assets/javascripts/effective_datatables/events.js.coffee +7 -0
  10. data/app/assets/javascripts/effective_datatables/filters.js.coffee +6 -0
  11. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +42 -39
  12. data/app/assets/javascripts/effective_datatables/reset.js.coffee +7 -0
  13. data/app/assets/javascripts/vendor/jquery.delayedChange.js +1 -1
  14. data/app/assets/stylesheets/dataTables/dataTables.bootstrap.css +0 -1
  15. data/app/assets/stylesheets/effective_datatables.scss +1 -2
  16. data/app/assets/stylesheets/effective_datatables/{_scopes.scss → _filters.scss} +1 -1
  17. data/app/assets/stylesheets/effective_datatables/_overrides.scss +1 -1
  18. data/app/controllers/effective/datatables_controller.rb +2 -4
  19. data/app/helpers/effective_datatables_helper.rb +56 -91
  20. data/app/helpers/effective_datatables_private_helper.rb +55 -64
  21. data/app/models/effective/datatable.rb +103 -177
  22. data/app/models/effective/datatable_column.rb +28 -0
  23. data/app/models/effective/datatable_column_tool.rb +110 -0
  24. data/app/models/effective/datatable_dsl_tool.rb +28 -0
  25. data/app/models/effective/datatable_value_tool.rb +142 -0
  26. data/app/models/effective/effective_datatable/attributes.rb +25 -0
  27. data/app/models/effective/effective_datatable/collection.rb +38 -0
  28. data/app/models/effective/effective_datatable/compute.rb +154 -0
  29. data/app/models/effective/effective_datatable/cookie.rb +29 -0
  30. data/app/models/effective/effective_datatable/dsl.rb +14 -8
  31. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +5 -6
  32. data/app/models/effective/effective_datatable/dsl/charts.rb +7 -9
  33. data/app/models/effective/effective_datatable/dsl/datatable.rb +107 -57
  34. data/app/models/effective/effective_datatable/dsl/filters.rb +50 -0
  35. data/app/models/effective/effective_datatable/format.rb +157 -0
  36. data/app/models/effective/effective_datatable/hooks.rb +0 -18
  37. data/app/models/effective/effective_datatable/params.rb +34 -0
  38. data/app/models/effective/effective_datatable/resource.rb +108 -0
  39. data/app/models/effective/effective_datatable/state.rb +178 -0
  40. data/app/views/effective/datatables/_actions_column.html.haml +9 -42
  41. data/app/views/effective/datatables/_bulk_actions_column.html.haml +1 -1
  42. data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +2 -3
  43. data/app/views/effective/datatables/_chart.html.haml +1 -1
  44. data/app/views/effective/datatables/_datatable.html.haml +7 -25
  45. data/app/views/effective/datatables/_filters.html.haml +21 -0
  46. data/app/views/effective/datatables/_reset.html.haml +2 -0
  47. data/app/views/effective/datatables/_resource_column.html.haml +8 -0
  48. data/app/views/effective/datatables/index.html.haml +0 -1
  49. data/config/effective_datatables.rb +9 -32
  50. data/lib/effective_datatables.rb +2 -6
  51. data/lib/effective_datatables/engine.rb +1 -1
  52. data/lib/effective_datatables/version.rb +1 -1
  53. data/lib/generators/effective_datatables/install_generator.rb +2 -2
  54. metadata +39 -19
  55. data/app/assets/javascripts/dataTables/colreorder/dataTables.colReorder.js +0 -27
  56. data/app/assets/javascripts/dataTables/jszip/jszip.js +0 -9155
  57. data/app/assets/javascripts/effective_datatables/scopes.js.coffee +0 -9
  58. data/app/models/effective/active_record_datatable_tool.rb +0 -242
  59. data/app/models/effective/array_datatable_tool.rb +0 -97
  60. data/app/models/effective/effective_datatable/ajax.rb +0 -101
  61. data/app/models/effective/effective_datatable/charts.rb +0 -20
  62. data/app/models/effective/effective_datatable/dsl/scopes.rb +0 -23
  63. data/app/models/effective/effective_datatable/helpers.rb +0 -24
  64. data/app/models/effective/effective_datatable/options.rb +0 -309
  65. data/app/models/effective/effective_datatable/rendering.rb +0 -365
  66. data/app/views/effective/datatables/_scopes.html.haml +0 -21
@@ -1,112 +1,103 @@
1
- # These aren't expected to be called by a developer.
2
- # They are internal datatables methods, but you could still call them on the view.
1
+ # These aren't expected to be called by a developer. They are internal methods.
3
2
  module EffectiveDatatablesPrivateHelper
4
3
 
5
- def datatable_default_order(datatable)
6
- [datatable.order_index, datatable.order_direction.downcase].to_json()
7
- end
8
-
9
4
  # https://datatables.net/reference/option/columns
10
5
  def datatable_columns(datatable)
11
6
  form = nil
12
- simple_form_for(:datatable_filter, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| form = f }
7
+ simple_form_for(:datatable_search, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| form = f }
13
8
 
14
- datatable.table_columns.map do |name, options|
9
+ datatable.columns.map do |name, opts|
15
10
  {
16
- name: options[:name],
17
- title: content_tag(:span, options[:label], class: 'filter-label'),
18
- className: options[:class],
19
- width: options[:width],
20
- responsivePriority: (options[:responsivePriority] || 10000), # 10,000 is datatables default
21
- sortable: (options[:sortable] && !datatable.simple?),
22
- visible: (options[:visible].respond_to?(:call) ? datatable.instance_exec(&options[:visible]) : options[:visible]),
23
- filterHtml: (datatable_header_filter(form, name, datatable.search_terms[name], options) unless datatable.simple?),
24
- filterSelectedValue: options[:filter][:selected]
11
+ name: name,
12
+ title: content_tag(:span, opts[:label], class: 'search-label'),
13
+ className: opts[:col_class],
14
+ searchHtml: (datatable_search_html(form, name, datatable.state[:search][name], opts) unless datatable.simple?),
15
+ responsivePriority: opts[:responsive],
16
+ search: datatable.state[:search][name],
17
+ sortable: (opts[:sort] && !datatable.simple?),
18
+ visible: datatable.state[:visible][name],
25
19
  }
26
- end.to_json()
20
+ end.to_json
27
21
  end
28
22
 
29
23
  def datatable_bulk_actions(datatable)
30
- bulk_actions_column = datatable.table_columns.find { |_, options| options[:bulk_actions_column] }.try(:second)
31
- return false unless bulk_actions_column
24
+ render(partial: '/effective/datatables/bulk_actions_dropdown', locals: { datatable: datatable }) if datatable._bulk_actions.present?
25
+ end
32
26
 
33
- {
34
- dropdownHtml: render(
35
- partial: bulk_actions_column[:dropdown_partial],
36
- locals: { datatable: datatable, dropdown_block: bulk_actions_column[:dropdown_block] }.merge(bulk_actions_column[:partial_locals])
37
- )
38
- }.to_json()
27
+ def datatable_reset(datatable)
28
+ render(partial: '/effective/datatables/reset', locals: { datatable: datatable })
39
29
  end
40
30
 
41
- def datatable_header_filter(form, name, value, opts)
42
- return render(partial: opts[:header_partial], locals: {form: form, name: (opts[:label] || name), column: opts}) if opts[:header_partial].present?
31
+ def datatable_search_html(form, name, value, opts)
32
+ include_blank = opts[:search].key?(:include_blank) ? opts[:search][:include_blank] : opts[:label]
33
+ pattern = opts[:search][:pattern]
34
+ placeholder = opts[:search][:placeholder] || ''
35
+ title = opts[:search][:title] || opts[:label]
36
+ wrapper_html = { class: 'datatable_search' }
43
37
 
44
- include_blank = opts[:filter].key?(:include_blank) ? opts[:filter][:include_blank] : (opts[:label] || name.titleize)
45
- pattern = opts[:filter].key?(:pattern) ? opts[:filter][:pattern] : nil
46
- placeholder = (opts[:filter][:placeholder] || '')
47
- title = opts[:filter].key?(:title) ? opts[:filter][:title] : (opts[:label] || name.titleize)
48
- wrapper_html = { class: 'datatable_filter' }
38
+ input_html = {
39
+ name: nil,
40
+ value: value,
41
+ title: title,
42
+ pattern: pattern,
43
+ autocomplete: 'off',
44
+ data: {'column-name' => name, 'column-index' => opts[:index]}
45
+ }.delete_if { |k, v| v.blank? && k != :name }
49
46
 
50
- case opts[:filter][:as]
47
+ case opts[:search][:as]
51
48
  when :string, :text, :number
52
49
  form.input name, label: false, required: false, value: value,
53
50
  as: :string,
54
51
  placeholder: placeholder,
55
52
  wrapper_html: wrapper_html,
56
- input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
57
- when :obfuscated_id
58
- pattern ||= '[0-9]{3}-?[0-9]{4}-?[0-9]{3}'
59
- title = opts[:filter].key?(:title) ? opts[:filter][:title] : 'Expected format: XXX-XXXX-XXX'
53
+ input_html: input_html
54
+ when :effective_obfuscation
55
+ input_html[:pattern] ||= '[0-9]{3}-?[0-9]{4}-?[0-9]{3}'
56
+ input_html[:title] = 'Expected format: XXX-XXXX-XXX'
60
57
 
61
58
  form.input name, label: false, required: false, value: value,
62
59
  as: :string,
63
- placeholder: placeholder.presence || '###-####-###',
60
+ placeholder: placeholder,
64
61
  wrapper_html: wrapper_html,
65
- input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
66
- when :date
62
+ input_html: input_html
63
+ when :date, :datetime
67
64
  form.input name, label: false, required: false, value: value,
68
65
  as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_picker) ? :effective_date_picker : :string),
69
66
  placeholder: placeholder,
70
67
  wrapper_html: wrapper_html,
71
68
  input_group: false,
72
- input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
69
+ input_html: input_html,
73
70
  input_js: { useStrict: true, keepInvalid: true }
74
- when :datetime
75
- form.input name, label: false, required: false, value: value,
76
- as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_time_picker) ? :effective_date_time_picker : :string),
77
- placeholder: placeholder,
78
- wrapper_html: wrapper_html,
79
- input_group: false,
80
- input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
81
- input_js: { useStrict: true, keepInvalid: true } # Keep invalid format like "2015-11" so we can still filter by year, month or day
71
+ # Keep invalid format like "2015-11" so we can still search by year, month or day
82
72
  when :select, :boolean
83
73
  form.input name, label: false, required: false, value: value,
84
74
  as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :select),
85
- collection: opts[:filter][:collection],
86
- selected: opts[:filter][:selected],
87
- multiple: opts[:filter][:multiple] == true,
75
+ collection: opts[:search][:collection],
76
+ selected: opts[:search][:value],
77
+ multiple: opts[:search][:multiple] == true,
88
78
  include_blank: include_blank,
89
79
  wrapper_html: wrapper_html,
90
- input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
80
+ input_html: input_html,
91
81
  input_js: { placeholder: placeholder }
92
82
  when :grouped_select
93
83
  form.input name, label: false, required: false, value: value,
94
84
  as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :grouped_select),
95
- collection: opts[:filter][:collection],
96
- selected: opts[:filter][:selected],
97
- multiple: opts[:filter][:multiple] == true,
98
- include_blank: include_blank,
85
+ collection: opts[:search][:collection],
86
+ selected: opts[:search][:value],
87
+ multiple: opts[:search][:multiple] == true,
99
88
  grouped: true,
100
- polymorphic: opts[:filter][:polymorphic] == true,
101
- group_label_method: opts[:filter][:group_label_method] || :first,
102
- group_method: opts[:filter][:group_method] || :last,
89
+ polymorphic: opts[:search][:polymorphic] == true,
90
+ group_label_method: opts[:search][:group_label_method] || :first,
91
+ group_method: opts[:search][:group_method] || :last,
103
92
  wrapper_html: wrapper_html,
104
- input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
93
+ input_html: input_html,
105
94
  input_js: { placeholder: placeholder }
106
- when :bulk_actions_column
95
+ when :bulk_actions
96
+ input_html[:data]['role'] = 'bulk-actions-all'
97
+
107
98
  form.input name, label: false, required: false, value: nil,
108
99
  as: :boolean,
109
- input_html: { name: nil, value: nil, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index], 'role' => 'bulk-actions-all'} }
100
+ input_html: input_html
110
101
  end
111
102
  end
112
103
 
@@ -1,234 +1,160 @@
1
1
  module Effective
2
2
  class Datatable
3
- attr_accessor :display_records, :view, :attributes
4
-
5
- # These two options control the render behaviour of a datatable
6
- attr_accessor :table_html_class, :simple
7
-
8
- delegate :render, :controller, :link_to, :mail_to, :number_to_currency, :number_to_percentage, :to => :@view
3
+ attr_reader :attributes # Anything that we initialize our table with. That's it. Can't be changed by state.
4
+ attr_reader :resource
5
+ attr_reader :state
6
+
7
+ # Hashes of DSL options
8
+ attr_reader :_aggregates
9
+ attr_reader :_bulk_actions
10
+ attr_reader :_charts
11
+ attr_reader :_columns
12
+ attr_reader :_filters
13
+ attr_reader :_form
14
+ attr_reader :_scopes
15
+
16
+ # The collection itself. Only evaluated once.
17
+ attr_accessor :_collection
18
+
19
+ # The view, and the ajax/cookie/default state
20
+ attr_reader :cookie
21
+ attr_reader :view
9
22
 
10
23
  extend Effective::EffectiveDatatable::Dsl
11
24
 
12
- include Effective::EffectiveDatatable::Dsl::BulkActions
13
- include Effective::EffectiveDatatable::Dsl::Charts
14
- include Effective::EffectiveDatatable::Dsl::Datatable
15
- include Effective::EffectiveDatatable::Dsl::Scopes
16
-
17
- include Effective::EffectiveDatatable::Ajax
18
- include Effective::EffectiveDatatable::Charts
19
- include Effective::EffectiveDatatable::Helpers
25
+ include Effective::EffectiveDatatable::Attributes
26
+ include Effective::EffectiveDatatable::Collection
27
+ include Effective::EffectiveDatatable::Compute
28
+ include Effective::EffectiveDatatable::Cookie
29
+ include Effective::EffectiveDatatable::Format
20
30
  include Effective::EffectiveDatatable::Hooks
21
- include Effective::EffectiveDatatable::Options
22
- include Effective::EffectiveDatatable::Rendering
23
-
24
- def initialize(*args)
25
- initialize_attributes(args)
31
+ include Effective::EffectiveDatatable::Params
32
+ include Effective::EffectiveDatatable::Resource
33
+ include Effective::EffectiveDatatable::State
26
34
 
27
- if respond_to?(:initialize_scopes) # There was at least one scope defined in the scopes do .. end block
28
- initialize_scopes
29
- initialize_scope_options
30
- end
31
-
32
- if respond_to?(:initialize_datatable)
33
- initialize_datatable # This creates @table_columns based on the DSL datatable do .. end block
34
- initialize_datatable_options # This normalizes all the options
35
- end
35
+ def initialize(view = nil, attributes = {})
36
+ (attributes = view; view = nil) if view.kind_of?(Hash)
36
37
 
37
- if respond_to?(:initialize_charts)
38
- initialize_charts
39
- initialize_chart_options
40
- end
38
+ @attributes = initial_attributes(attributes)
39
+ @state = initial_state
41
40
 
42
- unless active_record_collection? || array_collection?
43
- raise "Unsupported collection type. Should be ActiveRecord class, ActiveRecord relation, or an Array of Arrays [[1, 'something'], [2, 'something else']]"
44
- end
41
+ @_aggregates = {}
42
+ @_bulk_actions = []
43
+ @_charts = {}
44
+ @_columns = {}
45
+ @_filters = {}
46
+ @_form = {}
47
+ @_scopes = {}
45
48
 
46
- if @default_order.present? && !table_columns.key?((@default_order.keys.first rescue nil))
47
- raise "default_order :#{(@default_order.keys.first rescue 'nil')} must exist as a table_column or array_column"
48
- end
49
+ raise 'collection is defined as a method. Please use the collection do ... end syntax.' unless collection.nil?
50
+ self.view = view if view
49
51
  end
50
52
 
51
- def table_columns
52
- @table_columns
53
- end
53
+ # Once the view is assigned, we initialize everything
54
+ def view=(view)
55
+ @view = (view.respond_to?(:view_context) ? view.view_context : view)
56
+ raise 'expected view to respond to params' unless @view.respond_to?(:params)
54
57
 
55
- def scopes
56
- @scopes
57
- end
58
+ load_cookie!
59
+ load_attributes!
58
60
 
59
- def klass_scopes
60
- scopes.select { |name, options| options[:klass_scope] }
61
- end
61
+ # We need early access to filter and scope, to define defaults from the model first
62
+ # This means filters do knows about attributes but not about columns.
63
+ initialize_filters if respond_to?(:initialize_filters)
64
+ load_filters!
65
+ load_state!
62
66
 
63
- def current_scope # The currently selected (klass) scope
64
- attributes[:current_scope]
65
- end
67
+ # Now we initialize all the columns. columns knows about attributes and filters and scope
68
+ initialize_datatable if respond_to?(:initialize_datatable)
69
+ load_columns!
66
70
 
67
- def permitted_params
68
- scopes.keys + [:current_scope, :referer]
69
- end
71
+ # Execute any additional DSL methods
72
+ initialize_bulk_actions if respond_to?(:initialize_bulk_actions)
73
+ initialize_charts if respond_to?(:initialize_charts)
70
74
 
71
- def charts
72
- @charts
73
- end
75
+ # Load the collection. This is the first time def collection is called on the Datatable itself
76
+ initialize_collection if respond_to?(:initialize_collection)
77
+ load_collection!
74
78
 
75
- def aggregates
76
- @aggregates
77
- end
79
+ # Figure out the class, and if it's activerecord, do all the resource discovery on it
80
+ load_resource!
78
81
 
79
- # Any attributes set on initialize will be echoed back and available to the class
80
- def attributes
81
- @attributes ||= HashWithIndifferentAccess.new
82
+ save_cookie!
82
83
  end
83
84
 
84
- def to_key; []; end # Searching & Filters
85
+ def present?(view = nil)
86
+ unless (@view || view)
87
+ raise 'unable to call present? without an assigned view. In your view, either call render_datatable(@datatable) first, or use @datatable.present?(self)'
88
+ end
85
89
 
86
- # Instance method. In Rails 4.2 this needs to be defined on the instance, before it was on the class
87
- def model_name # Searching & Filters
88
- @model_name ||= ActiveModel::Name.new(self.class)
89
- end
90
+ self.view ||= view
90
91
 
91
- def self.model_name # Searching & Filters
92
- @model_name ||= ActiveModel::Name.new(self)
92
+ to_json[:recordsTotal] > 0
93
93
  end
94
94
 
95
- def to_param
96
- @to_param ||= self.class.name.underscore
97
- end
95
+ def blank?(view = nil)
96
+ unless (@view || view)
97
+ raise 'unable to call blank? without an assigned view. In your view, either call render_datatable(@datatable) first, or use @datatable.blank?(self)'
98
+ end
98
99
 
99
- def collection
100
- raise "You must define a collection. Something like an ActiveRecord User.all or an Array of Arrays [[1, 'something'], [2, 'something else']]"
101
- end
100
+ self.view ||= view
102
101
 
103
- def collection_class # This is set by initialize_datatable_options()
104
- @collection_class # Will be either User/Post/etc or Array
102
+ to_json[:recordsTotal] == 0
105
103
  end
106
104
 
107
105
  def to_json
108
- 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?
109
-
110
- @json ||= begin
111
- data = table_data
112
-
106
+ @json ||= (
113
107
  {
108
+ data: (compute || []),
114
109
  draw: (params[:draw] || 0),
115
- data: (data || []),
116
- recordsTotal: (total_records || 0),
117
- recordsFiltered: (display_records || 0),
118
- aggregates: (aggregate_data(data) || []),
119
- charts: (charts_data || {})
110
+ recordsTotal: (@total_records || 0),
111
+ recordsFiltered: (@display_records || 0),
112
+ aggregates: (@aggregates_data || []),
113
+ charts: (@charts_data || {})
120
114
  }
121
- end
122
- end
123
-
124
- def present?
125
- total_records > 0 || current_scope.present?
126
- end
127
-
128
- def empty?
129
- total_records == 0 && current_scope.blank?
130
- end
131
-
132
- def total_records
133
- @total_records ||= (active_record_collection? ? active_record_collection_size(the_collection) : the_collection.size)
134
- end
135
-
136
- def view=(view_context)
137
- @view = view_context
138
- @view.formats = [:html]
139
-
140
- # 'Just work' with attributes
141
- @view.class.send(:attr_accessor, :attributes)
142
- @view.attributes = self.attributes
143
-
144
- # Delegate any methods defined on the datatable directly to our view
145
- @view.class.send(:attr_accessor, :effective_datatable)
146
- @view.effective_datatable = self
147
-
148
- unless @view.respond_to?(:bulk_action)
149
- @view.class.send(:include, Effective::EffectiveDatatable::Dsl::BulkActions)
150
- end
151
-
152
- Effective::EffectiveDatatable::Helpers.instance_methods(false).each do |helper_method|
153
- @view.class_eval { delegate helper_method, to: :@effective_datatable }
154
- end
155
-
156
- (self.class.instance_methods(false) - [:initialize_datatable, :collection, :search_column, :order_column]).each do |view_method|
157
- @view.class_eval { delegate view_method, to: :@effective_datatable }
158
- end
159
-
160
- # Clear the search_terms memoization
161
- @search_terms = nil
162
- @order_name = nil
163
- @order_direction = nil
164
- end
165
-
166
- def view_context
167
- view
168
- end
169
-
170
- def table_html_class
171
- @table_html_class.presence || 'table table-bordered table-striped'
115
+ )
172
116
  end
173
117
 
174
118
  # When simple only a table will be rendered with
175
119
  # no sorting, no filtering, no export buttons, no pagination, no per page, no colReorder
176
120
  # default sorting only, default visibility only, all records returned, and responsive enabled
177
121
  def simple?
178
- @simple == true
122
+ attributes[:simple] == true
179
123
  end
180
124
 
181
- protected
125
+ # Whether the filters must be rendered as a <form> or we can keep the normal <div> behaviour
126
+ def _filters_form_required?
127
+ _form[:verb].present?
128
+ end
182
129
 
183
- def the_collection
184
- @memoized_collection ||= collection
130
+ def table_html_class
131
+ attributes[:class] || 'table table-bordered table-striped'
185
132
  end
186
133
 
187
- def params
188
- view.try(:params) || HashWithIndifferentAccess.new()
134
+ def to_param
135
+ @to_param ||= self.class.name.underscore.parameterize
189
136
  end
190
137
 
191
- def table_tool
192
- @table_tool ||= ActiveRecordDatatableTool.new(self, table_columns.reject { |_, col| col[:array_column] })
138
+ def columns
139
+ @_columns
193
140
  end
194
141
 
195
- def array_tool
196
- @array_tool ||= ArrayDatatableTool.new(self, table_columns.select { |_, col| col[:array_column] })
142
+ def collection
143
+ @_collection
197
144
  end
198
145
 
199
- # TODO
200
- # Check if collection has an order() clause and warn about it
201
- # Usually that will make the table results look weird.
202
- def active_record_collection?
203
- @active_record_collection == true
146
+ def dsl_tool
147
+ @dsl_tool ||= DatatableDslTool.new(self)
204
148
  end
205
149
 
206
- def array_collection?
207
- @array_collection == true
150
+ private
151
+
152
+ def column_tool
153
+ @column_tool ||= DatatableColumnTool.new(self)
208
154
  end
209
155
 
210
- # Not every ActiveRecord query will work when calling the simple .count
211
- # Custom selects:
212
- # User.select(:email, :first_name).count will throw an error
213
- # .count(:all) and .size seem to work
214
- # Grouped Queries:
215
- # User.all.group(:email).count will return a Hash
216
- def active_record_collection_size(collection)
217
- count = (collection.size rescue nil)
218
-
219
- case count
220
- when Integer
221
- count
222
- when Hash
223
- count.size # This represents the number of displayed datatable rows, not the sum all groups (which might be more)
224
- else
225
- if collection.klass.connection.respond_to?(:unprepared_statement)
226
- collection_sql = collection.klass.connection.unprepared_statement { collection.to_sql }
227
- (collection.klass.connection.exec_query("SELECT COUNT(*) FROM (#{collection_sql}) AS datatables_total_count").rows[0][0] rescue 1)
228
- else
229
- (collection.klass.connection.exec_query("SELECT COUNT(*) FROM (#{collection.to_sql}) AS datatables_total_count").rows[0][0] rescue 1)
230
- end.to_i
231
- end
156
+ def value_tool
157
+ @value_tool ||= DatatableValueTool.new(self)
232
158
  end
233
159
 
234
160
  end