action_tabler 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -117,8 +117,8 @@ See the DataTables web site for more about DataTables [Options](http://www.datat
117
117
 
118
118
  DataTables options which start with m or fn are treated differently, since they can be used to pass context specific Javascript. These options accept three three kinds of value:
119
119
 
120
- - String: This can be simply a string which will be rendered as is, or the name of a a partial to be rendered. The options local variable will be the current column definition hash.
121
- - Symbol: the name of a helper method which will be executed with a single argument containing the current column definition hash.
120
+ - String: a string which will be evaluated as is;
121
+ - Symbol: the name of a helper method which will be executed with a single argument containing the current column definition hash; or,
122
122
  - Proc: a Proc which will passed the current column definition hash.
123
123
 
124
124
  ## Running Tests
@@ -1,7 +1,7 @@
1
- <table cellpadding="0" cellspacing="0" border="0"<% if @table_class %> class="@table_class"<% end %> id="<%= @table_id %>">
1
+ <table cellpadding="0" cellspacing="0" border="0"<% if table_handler.table_class %> class="table_class"<% end %> id="<%= table_handler.table_id %>">
2
2
  <thead>
3
3
  <tr>
4
- <% for column in @table_columns do %>
4
+ <% for column in table_handler.columns do %>
5
5
  <th><%= column[:label] %></th>
6
6
  <% end %>
7
7
  </tr>
@@ -15,6 +15,6 @@
15
15
 
16
16
  <script type="text/javascript" charset="utf-8">
17
17
  $(document).ready(function() {
18
- $('#<%= @table_id %>').dataTable( <%= render_datatables_table_definitions.html_safe %> );
18
+ $('#<%= table_handler.table_id %>').dataTable( <%= table_handler.table_definition(params, url_for).html_safe %> );
19
19
  } );
20
20
  </script>
@@ -0,0 +1,88 @@
1
+ module ActionTabler
2
+ module DataTables
3
+ module DataHandler
4
+
5
+ # Render table data
6
+ def data_package(params)
7
+ # Select the requested records
8
+ @records = @model.where(exitisting_conditions(params)).
9
+ where(global_conditions(params)).
10
+ where(column_conditions(params)).
11
+ limit(params[:iDisplayLength]).
12
+ offset(params[:iDisplayStart]).
13
+ order(sort_conditions(params))
14
+ # Count the total records available
15
+ @display_count = @model.where(exitisting_conditions(params)).
16
+ where(global_conditions(params)).
17
+ where(column_conditions(params)).
18
+ count
19
+ # Find out total records, including those not found by a search specification
20
+ @total_count = @model.where(exitisting_conditions(params)).count
21
+
22
+ @column_names = []
23
+
24
+ # Build a hash with json safe column names
25
+ @records = @records.inject([]) do |result, record|
26
+ result << @columns.inject([]) do |this, column|
27
+ this << eval("record.#{column[:name]}")
28
+ @column_names << column[:name].to_s
29
+ this
30
+ end
31
+ result
32
+ end
33
+
34
+ # Return the data package as a hash
35
+ { :iTotalDisplayRecords => @display_count,
36
+ :iTotalRecords => @total_count,
37
+ :sNames => @column_names,
38
+ :aaData => @records,
39
+ :sEcho => params[:sEcho].to_i }
40
+ end # datatable_json_index
41
+
42
+ private
43
+
44
+ # Calculate global finder were clause
45
+ def global_conditions(params)
46
+ # Check to see if there's a search parameter
47
+ unless params[:sSearch].to_s.empty?
48
+ # Build a LIKE condition string with searchable fields
49
+ # NOTE: This ignores client-side specified searchable fields
50
+ search_string = searchable_columns.collect {|c| "#{column_for_sql(column[:name])} LIKE :keyword"}.join(" OR ")
51
+
52
+ # Assemble the condition string along with the search parameter
53
+ [search_string, {:keyword => "%#{params[:sSearch].to_s}%"}]
54
+ end
55
+ end
56
+
57
+ # Calculate where clause for individual column filtering
58
+ def column_conditions(params)
59
+ searchable_columns.inject({}) do |result, column|
60
+ search_string = params["sSearch_#{@columns.index(column)}"].to_s
61
+ unless search_string.empty?
62
+ result[column[:name]] = search_string
63
+ end
64
+ result
65
+ end
66
+ end
67
+
68
+ # Returns the finder order clause
69
+ def sort_conditions(params)
70
+ sort_conditions = params.inject([]) do |result, (k, v)|
71
+ # Find all of the parameters which start with iSortCol
72
+ if k.match(/iSortCol_(\d+)/) && i = k.match(/iSortCol_(\d+)/)[1]
73
+ # Add this sort condition to the temporary array
74
+ if @columns[v.to_i][:sortable] != false
75
+ sort_column = column_for_sql(@columns[v.to_i][:name])
76
+ result << "#{sort_column} #{params['sSortDir_' + i.to_s]}"
77
+ end
78
+ end
79
+ result
80
+ end
81
+
82
+ # Join the array into a sort string
83
+ sort_conditions.join(", ").strip
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,107 @@
1
+ module ActionTabler
2
+ module DataTables
3
+ module DisplayHandler
4
+ def table_definition(params, source_url)
5
+ table_options = {:bProcessing => true, :bServerSide => true, :sAjaxSource => source_url}.update(@table_options)
6
+ table_options[:fnServerParams] ||= passed_parameters(exitisting_conditions(params))
7
+ table_options[:aoColumnDefs] ||= column_definitions
8
+
9
+ "{" + table_options.collect{|k,v| render_attribute(k, v)}.compact.join(", \n") + "}"
10
+ end # table_definition
11
+
12
+ def table_id
13
+ @model.name.underscore + "_table"
14
+ end
15
+
16
+ def table_class
17
+ @table_class
18
+ end
19
+
20
+ def columns
21
+ @columns
22
+ end
23
+
24
+ private
25
+
26
+ # Build the DataTables column definition list
27
+ def column_definitions
28
+ count = -1
29
+ @columns.collect {|column| count += 1; column_definition_for(column, count)}
30
+ end # column_definitions
31
+
32
+ # Build an individual DataTables column definition
33
+ def column_definition_for(column, count)
34
+ this_column = column.clone
35
+ this_column.delete(:label)
36
+ this_column[:sName] = this_column.delete(:name)
37
+
38
+ this_column[:sType] ||= column_type_for(column[:name]) if @auto_type
39
+
40
+ this_column[:bSearchable] = this_column.delete(:searchable) if this_column.has_key?(:searchable)
41
+ this_column[:bSortable] = this_column.delete(:sortable) if this_column.has_key?(:sortable)
42
+ this_column[:aTargets] = [count]
43
+
44
+ "{" + this_column.collect{|k,v| render_attribute(k, v, column)}.compact.join(", ") + "}"
45
+ end # column_definition_for
46
+
47
+ # Render passed parameters for a Data Table table definition
48
+ def passed_parameters(options)
49
+ "function ( aoData ) { aoData.push( " +
50
+ options.collect{|k,v| '{ "name": "' + @model.name.parameterize +
51
+ '[' + k + ']", "value": "' + v + '"}' }.join(", ") +
52
+ " ); }" if options
53
+ end # passed_parameters
54
+
55
+ # Render an attribute for a DataTables column definition
56
+ def render_attribute(name, value, options = {})
57
+ this_name = name.to_s
58
+ if value.nil?
59
+ return
60
+ elsif this_name.starts_with?("b")
61
+ '"' + this_name + '": ' + (value ? 'true' : 'false')
62
+ elsif this_name.starts_with?("i")
63
+ '"' + this_name + '": "' + value.to_i.to_s + '"'
64
+ elsif this_name.starts_with?("ao")
65
+ '"' + this_name + '": ' + "[#{value.join(", \n")}]"
66
+ elsif this_name.starts_with?("a")
67
+ '"' + this_name + '": ' + value.to_json.html_safe
68
+ elsif this_name.starts_with?("fn", "m")
69
+ '"' + this_name + '": ' + render_fn_or_m_attribute(value, options)
70
+ elsif this_name.starts_with?("f")
71
+ '"' + this_name + '": "' + value.to_f.to_s + '"'
72
+ else
73
+ '"' + this_name + '": "' + value.to_s + '"'
74
+ end
75
+ end #render_attribute
76
+
77
+ # Render a function or method column attribute for a DataTables column definition.
78
+ def render_fn_or_m_attribute(value, options)
79
+ if value.kind_of?(Proc)
80
+ value.call(options)
81
+ elsif value.kind_of?(Symbol)
82
+ self.send(value, options)
83
+ elsif value.kind_of?(String)
84
+ value
85
+ else
86
+ ""
87
+ end
88
+ end # render_fn_or_m_attribute
89
+
90
+ def column_type_for(name)
91
+ visit_attribute(name) do |name, model|
92
+ case model.columns_hash[name].class
93
+ when :datetime, :date, :time, :timestamp
94
+ "date"
95
+ when :integer, :float, :decimal, :binary
96
+ "numeric"
97
+ when :text
98
+ "html"
99
+ else
100
+ "string"
101
+ end
102
+ end
103
+ end # column_type_for
104
+
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,9 @@
1
+ require 'action_tabler/data_tables/display_handler'
2
+ require 'action_tabler/data_tables/data_handler'
3
+
4
+ module ActionTabler
5
+ module DataTables
6
+ include ActionTabler::DataTables::DataHandler
7
+ include ActionTabler::DataTables::DisplayHandler
8
+ end
9
+ end
@@ -3,333 +3,38 @@ module ActionTabler
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- class_attribute :action_tabler_columns, :action_tabler_action, :action_tabler_auto_type,
7
- :action_tabler_pass_params, :action_tabler_model, :action_tabler_table_class,
8
- :action_tabler_auto_width, :action_tabler_table_options
6
+ class_attribute :table_handler
9
7
  end
10
8
 
11
9
  module ClassMethods
12
10
  # Adds table display to a controller.
13
- def has_table_action(columns = [], options = {})
14
- self.action_tabler_columns = []
15
- self.action_tabler_table_options = {}
16
-
17
- # Load essential column-related options
18
- self.action_tabler_model = (options[:class_name] || controller_name).classify.constantize
19
- self.action_tabler_auto_type = options[:auto_type] || AbstractController::Base.action_tabler_auto_type
20
-
21
- # Check to see what we've been passed
22
- if columns.kind_of?(Hash)
23
- # Set options to columns if columns not passed in parameters
24
- options = columns
25
- elsif columns == :auto
26
- # Auto populate columns if specified
27
- auto_table_columns
28
- elsif columns.kind_of?(Array)
29
- columns.collect{|c| column(c)}
30
- end
31
-
32
- # Populate columns from block
33
- yield if block_given?
34
-
35
- # Add configuration columns if specified
36
- if AbstractController::Base.action_tabler_columns.kind_of?(Array)
37
- AbstractController::Base.action_tabler_columns.collect{|c| column(c)}
38
- end
39
-
40
- # Auto specify columns if they're empty and the config is set to auto
41
- if action_tabler_columns.empty? && AbstractController::Base.action_tabler_columns == :auto
42
- auto_table_columns
43
- end
44
-
45
- if action_tabler_columns.empty?
46
- raise ArgumentError, "No columns defined for has_table_action"
47
- end
48
-
49
- # Load options
50
- self.action_tabler_action = options[:action] || AbstractController::Base.action_tabler_action
51
- self.action_tabler_pass_params = options[:pass_params] || AbstractController::Base.action_tabler_pass_params
52
- self.action_tabler_table_class = options[:table_class] || AbstractController::Base.action_tabler_table_class
53
-
54
- self.action_tabler_table_options.update(AbstractController::Base.action_tabler_table_options)
55
- self.action_tabler_table_options.update(options[:table_options] || {})
11
+ def has_table_action(columns = [], options = {}, &block)
12
+ self.table_handler = ActionTabler::Handler.new(self, columns, options, &block)
56
13
 
57
14
  include DeclaredInstanceMethods
58
15
 
59
16
  # Define the table action method
60
- define_method(action_tabler_action) do
17
+ define_method(options[:action] || ActionTabler::Handler.configuration[:action]) do
61
18
  action_tabler
62
19
  end
63
20
 
64
- # Make the column name formaters available in views
65
- helper_method :column_name_for_json, :column_name_from_json, :render_datatables_table_definitions
21
+ helper_method :table_handler
66
22
  end # has_table_action
67
23
 
68
- # Add a table column definition
69
- def column(name, opts={})
70
- # Check what we're getting
71
- if name.kind_of?(Hash)
72
- # If it's a hash, leave as is
73
- column = name
74
- raise ArgumentError, "column definition requires a name" if column[:name].to_s.empty?
75
- elsif name.kind_of?(Symbol) || name.kind_of?(String)
76
- # If it's a string or symbol, create a definition
77
- column = {:name => name}
78
- column.update(opts) if opts.kind_of?(Hash)
79
- else
80
- raise ArgumentError, "table_column name expects String, Symbol, or Hash (got #{name.class.name})"
81
- end
82
-
83
- # Ensure name is a string
84
- column[:name] = column[:name].to_s
85
-
86
- # Add label if not specified
87
- column[:label] ||= column[:name].to_s.titleize
88
-
89
- # Add the column to out list
90
- self.action_tabler_columns << column
91
- end
92
-
93
- # Create column definitions using reflection
94
- def auto_table_columns
95
- action_tabler_model.columns_hash.keys.collect{|k| column(k)}
96
- end
97
-
98
24
  end # ClassMethods
99
25
 
100
26
  module DeclaredInstanceMethods
101
27
 
102
- # Translate . to _dot_
103
- def column_name_for_json(name)
104
- name.gsub(".", "_dot_")
105
- end
106
-
107
- # Translate _dot_ to .
108
- def column_name_from_json(name)
109
- name.gsub("_dot_", ".")
110
- end
111
-
112
- def render_datatables_table_definitions
113
- table_options = {:bProcessing => true, :bServerSide => true, :sAjaxSource => url_for}.update(action_tabler_table_options)
114
- table_options[:fnServerParams] ||= render_passed_parameters(@table_parameters) if @table_parameters
115
- table_options[:aoColumnDefs] ||= datatables_column_definitions
116
-
117
- "{" + table_options.collect{|k,v| render_datatables_attribute(k, v)}.join(", \n") + "}"
118
- end
119
-
120
28
  private
121
29
 
122
30
  # Main table view action
123
31
  def action_tabler
124
- # Figure out what model with which we're working
125
- @table_model = action_tabler_model
126
-
127
- # Load the column specification
128
- @table_columns = action_tabler_columns
129
-
130
- # Assign addtional parameters
131
- @table_parameters = params[@table_model.name.parameterize] if action_tabler_pass_params
132
-
133
32
  respond_to do |format|
134
- format.html {action_tabler_for_html}
135
- format.json {action_tabler_for_json}
33
+ format.html {render "action_tabler/table"}
34
+ format.json {render :json => table_handler.data_package(params)}
136
35
  end # respond_to
137
36
  end # datatable_index
138
37
 
139
- ###
140
- # Display Rendering
141
- ###
142
-
143
- # Render the datable html index, which provides the browser display wrapper for the table data
144
- def action_tabler_for_html
145
- # Assign the table css class
146
- @table_class = action_tabler_table_class
147
-
148
- # Assign the table DOM id
149
- @table_id = @table_model.name.underscore + "_table"
150
-
151
- # Assign auto width setting
152
- @table_auto_width = action_tabler_auto_width
153
-
154
- render "action_tabler/table"
155
- end # datatable_html_index
156
-
157
- # Build the DataTables column definition list
158
- def datatables_column_definitions
159
- count = -1
160
- action_tabler_columns.collect {|col| count += 1; datatables_column_definition_for(col, count)}
161
- end # datatables_column_definitions
162
-
163
- # Build an individual DataTables column definition
164
- def datatables_column_definition_for(column, count)
165
- this_column = column.clone
166
- this_column.delete(:label)
167
- this_column[:sName] = this_column.delete(:name)
168
-
169
- this_column[:sType] ||= action_tabler_column_type_for(column[:name], action_tabler_model) if action_tabler_auto_type
170
-
171
- this_column[:bSearchable] = this_column.delete(:searchable) if this_column.has_key?(:searchable)
172
- this_column[:bSortable] = this_column.delete(:sortable) if this_column.has_key?(:sortable)
173
- this_column[:aTargets] = [count]
174
-
175
- "{" + this_column.collect{|k,v| render_datatables_attribute(k, v, column)}.compact.join(", ") + "}"
176
- end # datatables_column_definition_for
177
-
178
- # Render passed parameters for a Data Table table definition
179
- def render_passed_parameters(options)
180
- "function ( aoData ) { aoData.push( " +
181
- options.collect{|k,v| '{ "name": "' + @table_model.name.parameterize +
182
- '[' + k + ']", "value": "' + v + '"}' }.join(", ") +
183
- " ); }"
184
- end # render_pass_parameters
185
-
186
- # Render an attribute for a DataTables column definition
187
- def render_datatables_attribute(name, value, options = {})
188
- this_name = name.to_s
189
- if value.nil?
190
- return
191
- elsif this_name.starts_with?("b")
192
- '"' + this_name + '": ' + (value ? 'true' : 'false')
193
- elsif this_name.starts_with?("i")
194
- '"' + this_name + '": "' + value.to_i.to_s + '"'
195
- elsif this_name.starts_with?("ao")
196
- '"' + this_name + '": ' + "[#{value.join(", \n")}]"
197
- elsif this_name.starts_with?("a")
198
- '"' + this_name + '": ' + value.to_json.html_safe
199
- elsif this_name.starts_with?("fn", "m")
200
- '"' + this_name + '": ' + render_datatables_fn_or_m(value, options)
201
- elsif this_name.starts_with?("f")
202
- '"' + this_name + '": "' + value.to_f.to_s + '"'
203
- else
204
- '"' + this_name + '": "' + value.to_s + '"'
205
- end
206
- end
207
-
208
- # Render a function or method column attribute for a DataTables column definition.
209
- def render_datatables_fn_or_m(value, options)
210
- if value.kind_of?(Proc)
211
- value.call(options)
212
- elsif value.kind_of?(Symbol)
213
- self.send(value, options)
214
- elsif value.kind_of?(String)
215
- lookup_context.formats << :js
216
- template_exists?(value, lookup_context.prefixes, true) ? render_to_string(:partial => value, :locals => {:options => options}) : value
217
- else
218
- ""
219
- end
220
- end
221
-
222
- # Look up an ActiveRecord column type and translate to DataTables column type.
223
- def action_tabler_column_type_for(name, model=nil)
224
- # Set the default model if not passed
225
- model ||= action_tabler_model
226
-
227
- # We can really only do this if we have ActiveRecord or equivalent
228
- return nil unless model.respond_to?(:columns_hash)
229
-
230
- # Ensure we have a string
231
- name = name.to_s
232
-
233
- # Determine if we have a relation
234
- if name.include?(".")
235
- names = name.split(".")
236
- # Discover relation model name
237
- reflection = model.reflect_on_association(names[0].to_sym)
238
- # Recurse with realtion model and name
239
- action_tabler_column_type_for(name.gsub("#{names[0]}.", ""), reflection.klass)
240
- else
241
- # Look up and return the Datatables column type
242
- ActionTabler::JqueryDatatables.column_type_for(model.columns_hash[name].class)
243
- end
244
- end
245
-
246
- ###
247
- # Data Rendering
248
- ###
249
-
250
- # Render the table data
251
- def action_tabler_for_json
252
- # Select the requested records
253
- @records = @table_model.where(@table_parameters).
254
- where(action_tabler_global_conditions).
255
- where(action_tabler_column_conditions).
256
- limit(params[:iDisplayLength]).
257
- offset(params[:iDisplayStart]).
258
- order(action_tabler_sort_order)
259
- # Count the total records available
260
- records_count = @table_model.where(@table_parameters).
261
- where(action_tabler_global_conditions).
262
- where(action_tabler_column_conditions).
263
- count
264
- # Find out total records, including those not found by a search specification
265
- total_count = @table_model.where(@table_parameters).count
266
-
267
- @column_names = []
268
-
269
- # Build a hash with json safe column names
270
- @records = @records.inject([]) do |result, record|
271
- result << action_tabler_columns.inject([]) do |this, column|
272
- this << eval("record.#{column[:name]}")
273
- @column_names << column[:name].to_s
274
- this
275
- end
276
- result
277
- end
278
-
279
- # Render the data as json
280
- render :json => { :iTotalRecords => total_count,
281
- :iTotalDisplayRecords => records_count,
282
- :sNames => @column_names,
283
- :aaData => @records,
284
- :sEcho => params[:sEcho].to_i }
285
- end # datatable_json_index
286
-
287
- # Calculate global finder were clause
288
- def action_tabler_global_conditions
289
- # Check to see if there's a search parameter
290
- unless params[:sSearch].to_s.empty?
291
- # Build a LIKE condition string with searchable fields
292
- # NOTE: This ignores client-side specified searchable fields
293
- search_string = action_tabler_searchable_columns.collect {|c| "#{column[:name]} LIKE :keyword"}.join(" OR ")
294
-
295
- # Assemble the condition string along with the search parameter
296
- [search_string, {:keyword => "%#{params[:sSearch].to_s}%"}]
297
- end
298
- end
299
-
300
- # Calculate where clause for individual column filtering
301
- def action_tabler_column_conditions
302
- action_tabler_searchable_columns.inject({}) do |result, column|
303
- search_string = params["sSearch_#{action_tabler_columns.index(column)}"].to_s
304
- unless search_string.empty?
305
- result[column[:name]] = search_string
306
- end
307
- result
308
- end
309
- end
310
-
311
- # List searchable columns
312
- def action_tabler_searchable_columns
313
- action_tabler_columns.select{|column| column[:searchable] != false}
314
- end
315
-
316
- # Returns the finder order clause
317
- def action_tabler_sort_order
318
- sort_conditions = params.inject([]) do |result, (k, v)|
319
- # Find all of the parameters which start with iSortCol
320
- if k.match(/iSortCol_(\d+)/) && i = k.match(/iSortCol_(\d+)/)[1]
321
- # Add this sort condition to the temporary array
322
- if action_tabler_columns[v.to_i][:sortable] != false
323
- result << "#{action_tabler_columns[v.to_i][:name]} #{params['sSortDir_' + i.to_s]}"
324
- end
325
- end
326
- result
327
- end
328
-
329
- # Join the array into a sort string
330
- sort_conditions.join(", ").strip
331
- end
332
-
333
38
  end # InstanceMethods
334
39
  end #AbstractController
335
40
  end
@@ -15,28 +15,27 @@ module ActionTabler
15
15
  end
16
16
 
17
17
  def initialize_configuration(config)
18
+ ActionTabler::Handler.configuration = {}
18
19
 
19
20
  # Check and set default column definitions
20
21
  if config.respond_to?(:action_tabler_columns)
21
22
  if config.action_tabler_columns.kind_of?(Array) ||
22
- config.action_tabler_columns.kind_of?(Symbol) ||
23
- config.action_tabler_columns.kind_of?(Proc)
24
- AbstractController::Base.action_tabler_columns = config.action_tabler_columns
23
+ config.action_tabler_columns.kind_of?(Symbol) ||
24
+ config.action_tabler_columns.kind_of?(Proc)
25
+ ActionTabler::Handler.configuration[:columns] = config.action_tabler_columns
25
26
  else
26
27
  raise ArgumentError, "config.action_tabler_columns expected Symbol, Array, or Proc (got #{config.action_tabler_attributes.class.name})"
27
28
  end
28
29
  else
29
- AbstractController::Base.action_tabler_columns = []
30
+ ActionTabler::Handler.configuration[:columns] = []
30
31
  end
31
32
 
32
33
  # Set other configuration options
33
- AbstractController::Base.action_tabler_columns = (config.respond_to?(:action_tabler_columns) ? config.action_tabler_columns : [])
34
- AbstractController::Base.action_tabler_table_class = config.respond_to?(:action_tabler_table_class) ? config.action_tabler_table_class : nil
35
- AbstractController::Base.action_tabler_auto_width = config.respond_to?(:action_tabler_auto_width) ? config.action_tabler_auto_width : true
36
- AbstractController::Base.action_tabler_action = config.respond_to?(:action_tabler_action) ? config.action_tabler_action : "table"
37
- AbstractController::Base.action_tabler_auto_type = config.respond_to?(:action_tabler_auto_type) ? config.action_tabler_auto_type : true
38
- AbstractController::Base.action_tabler_pass_params = config.respond_to?(:action_tabler_pass_params) ? config.action_tabler_pass_params : false
39
- AbstractController::Base.action_tabler_table_options = config.respond_to?(:action_tabler_table_options) ? config.action_tabler_table_options : {}
34
+ ActionTabler::Handler.configuration[:table_class] = config.respond_to?(:action_tabler_table_class) ? config.action_tabler_table_class : nil
35
+ ActionTabler::Handler.configuration[:action] = config.respond_to?(:action_tabler_action) ? config.action_tabler_action : "table"
36
+ ActionTabler::Handler.configuration[:auto_type] = config.respond_to?(:action_tabler_auto_type) ? config.action_tabler_auto_type : true
37
+ ActionTabler::Handler.configuration[:pass_params] = config.respond_to?(:action_tabler_pass_params) ? config.action_tabler_pass_params : false
38
+ ActionTabler::Handler.configuration[:table_options] = config.respond_to?(:action_tabler_table_options) ? config.action_tabler_table_options : {}
40
39
 
41
40
  end
42
41
  end
@@ -0,0 +1,83 @@
1
+ module ActionTabler
2
+ class Handler
3
+ class_attribute :configuration
4
+
5
+ include ActionTabler::Utilities
6
+ include ActionTabler::DataTables
7
+
8
+ def initialize(controller, columns = [], options = {}, &block)
9
+ @columns = []
10
+ @table_options = {}
11
+
12
+ # Load essential column-related options
13
+ @model = (options[:class_name] || controller.controller_name).classify.constantize
14
+ @auto_type = options[:auto_type] || configuration[:auto_type]
15
+
16
+ # Check to see what we've been passed
17
+ if columns.kind_of?(Hash)
18
+ # Set options to columns if columns not passed in parameters
19
+ options = columns
20
+ elsif columns == :auto
21
+ # Auto populate columns if specified
22
+ auto_columns
23
+ elsif columns.kind_of?(Array)
24
+ columns.collect{|c| column(c)}
25
+ end
26
+
27
+ # Populate columns from block
28
+ instance_eval(&block) if block.kind_of?(Proc)
29
+
30
+ # Add configuration columns if specified
31
+ if configuration[:columns].kind_of?(Array)
32
+ configuration[:columns].collect{|c| column(c)}
33
+ end
34
+
35
+ # Auto specify columns if they're empty and the config is set to auto
36
+ if @columns.empty? && configuration[:columns] == :auto
37
+ auto_columns
38
+ end
39
+
40
+ if @columns.empty?
41
+ raise ArgumentError, "No columns defined for has_table_action"
42
+ end
43
+
44
+ # Load options
45
+ @pass_params = options[:pass_params] || configuration[:pass_params]
46
+ @table_class = options[:table_class] || configuration[:table_class]
47
+
48
+ @table_options.update(configuration[:table_options])
49
+ @table_options.update(options[:table_options] || {})
50
+ end
51
+
52
+ # Add a table column definition
53
+ def column(name, opts={})
54
+ # Check what we're getting
55
+ if name.kind_of?(Hash)
56
+ # If it's a hash, leave as is
57
+ column = name
58
+ raise ArgumentError, "column definition requires a name" if column[:name].to_s.empty?
59
+ elsif name.kind_of?(Symbol) || name.kind_of?(String)
60
+ # If it's a string or symbol, create a definition
61
+ column = {:name => name}
62
+ column.update(opts) if opts.kind_of?(Hash)
63
+ else
64
+ raise ArgumentError, "table_column name expects String, Symbol, or Hash (got #{name.class.name})"
65
+ end
66
+
67
+ # Ensure name is a string
68
+ column[:name] = column[:name].to_s
69
+
70
+ # Add label if not specified
71
+ column[:label] ||= column[:name].to_s.gsub(".", " ").titleize
72
+
73
+ # Add the column to out list
74
+ @columns << column
75
+ end
76
+
77
+ # Create column definitions using reflection
78
+ def auto_columns
79
+ @model.columns_hash.keys.collect{|k| column(k)}
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,43 @@
1
+ module ActionTabler
2
+ module Utilities
3
+
4
+ # Existing search conditions if enabled
5
+ def exitisting_conditions(params)
6
+ params[@model.name.parameterize] if @pass_params
7
+ end
8
+
9
+ # List searchable columns
10
+ def searchable_columns
11
+ @columns.select{|column| column[:searchable] != false}
12
+ end
13
+
14
+ # Returns a fully qualified column name for SQL statements
15
+ def column_for_sql(name, model = nil)
16
+ visit_attribute(name){|name, model| [model.arel_table.name, name].join(".")}
17
+ end
18
+
19
+ # Helps work with fully qualified attributes, usually to generate SQL
20
+ def visit_attribute(name, model = nil, &block)
21
+ # Set the default model if not passed
22
+ model ||= @model
23
+
24
+ # We can really only do this if we have ActiveRecord or equivalent
25
+ return nil unless model.respond_to?(:columns_hash)
26
+
27
+ # Ensure we have a string
28
+ name = name.to_s
29
+
30
+ # Determine if we have a relation
31
+ if name.include?(".")
32
+ names = name.split(".")
33
+ # Discover relation model
34
+ reflection = model.reflect_on_association(names[0].to_sym)
35
+ # Recurse with realtion model and name
36
+ column_for_sql(name.gsub("#{names[0]}.", ""), reflection.klass)
37
+ else
38
+ block.call(name, model)
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module ActionTabler
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/action_tabler.rb CHANGED
@@ -1,31 +1,9 @@
1
- require 'action_tabler/jquery_datatables'
1
+ require 'action_tabler/utilities'
2
+ require 'action_tabler/data_tables'
3
+ require 'action_tabler/table_handler'
2
4
  require 'action_tabler/has_table_action'
3
5
  require 'action_tabler/mapper'
4
6
  require 'action_tabler/railtie' if defined?(Rails)
5
7
 
6
8
  module ActionTabler
7
- def initialize_configuration(config)
8
-
9
- # Check and set default column definitions
10
- if config.respond_to?(:action_tabler_columns)
11
- if config.action_tabler_columns.kind_of?(Array) ||
12
- config.action_tabler_columns.kind_of?(Symbol) ||
13
- config.action_tabler_columns.kind_of?(Proc)
14
- AbstractController::Base.action_tabler_columns = config.action_tabler_columns
15
- else
16
- raise ArgumentError, "config.action_tabler_columns expected Symbol, Array, or Proc (got #{config.action_tabler_attributes.class.name})"
17
- end
18
- else
19
- AbstractController::Base.action_tabler_columns = []
20
- end
21
-
22
- # Set other configuration options
23
- AbstractController::Base.action_tabler_columns = (config.respond_to?(:action_tabler_columns) ? config.action_tabler_columns : [])
24
- AbstractController::Base.action_tabler_table_class = config.respond_to?(:action_tabler_table_class) ? config.action_tabler_table_class : nil
25
- AbstractController::Base.action_tabler_auto_width = config.respond_to?(:action_tabler_auto_width) ? config.action_tabler_auto_width : true
26
- AbstractController::Base.action_tabler_action = config.respond_to?(:action_tabler_action) ? config.action_tabler_action : "table"
27
- AbstractController::Base.action_tabler_auto_type = config.respond_to?(:action_tabler_auto_type) ? config.action_tabler_auto_type : true
28
- AbstractController::Base.action_tabler_pass_params = config.respond_to?(:action_tabler_pass_params) ? config.action_tabler_pass_params : false
29
- AbstractController::Base.action_tabler_table_options = config.respond_to?(:action_tabler_table_options) ? config.action_tabler_table_options : {}
30
- end
31
9
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_tabler
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - lhalff
@@ -97,11 +97,14 @@ files:
97
97
  - app/views/action_tabler/_table_footer.html.erb
98
98
  - app/views/action_tabler/_table_header.html.erb
99
99
  - app/views/action_tabler/table.html.erb
100
- - lib/action_tabler/column_type_for.rb
100
+ - lib/action_tabler/data_tables/data_handler.rb
101
+ - lib/action_tabler/data_tables/display_handler.rb
102
+ - lib/action_tabler/data_tables.rb
101
103
  - lib/action_tabler/has_table_action.rb
102
- - lib/action_tabler/jquery_datatables.rb
103
104
  - lib/action_tabler/mapper.rb
104
105
  - lib/action_tabler/railtie.rb
106
+ - lib/action_tabler/table_handler.rb
107
+ - lib/action_tabler/utilities.rb
105
108
  - lib/action_tabler/version.rb
106
109
  - lib/action_tabler.rb
107
110
  - lib/tasks/table_view_tasks.rake
@@ -1,19 +0,0 @@
1
- module ActionTabler
2
- module ColumnTypeFor
3
- extend ActiveSupport::Concern
4
-
5
- module ClassMethods
6
- # Returns a display column type for an attribute using reflection.
7
- def action_tabler_column_type_for(attribute, model)
8
- attribute = attribute.to_s
9
- attributes = attribute.split(".")
10
- if attributes.length > 1
11
- reflection = model.reflect_on_association(attributes[0].to_sym)
12
- reflection.klass.action_tabler_column_type_for(attribute.gsub("#{attributes[0]}.", ""))
13
- else
14
- ActionTabler::JqueryDatatables.column_type_for(model.columns_hash[attribute].class)
15
- end
16
- end
17
- end # ClassMethods
18
- end # ActionTablerOptions
19
- end # ActionTabler
@@ -1,16 +0,0 @@
1
- module ActionTabler
2
- module JqueryDatatables
3
- def self.column_type_for(col_type)
4
- case col_type
5
- when :datetime, :date, :time, :timestamp
6
- "date"
7
- when :integer, :float, :decimal, :binary
8
- "numeric"
9
- when :text
10
- "html"
11
- else
12
- "string"
13
- end
14
- end
15
- end
16
- end