action_tabler 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +131 -0
- data/Rakefile +38 -0
- data/app/assets/javascripts/action_tabler.js +2 -0
- data/app/assets/stylesheets/action_tabler.css +1 -0
- data/app/assets/stylesheets/action_tabler_bootstrap.css +2 -0
- data/app/views/action_tabler/_comma_spacer.html.erb +1 -0
- data/app/views/action_tabler/_table.html.erb +20 -0
- data/app/views/action_tabler/_table_footer.html.erb +0 -0
- data/app/views/action_tabler/_table_header.html.erb +0 -0
- data/app/views/action_tabler/table.html.erb +3 -0
- data/lib/action_tabler/column_type_for.rb +19 -0
- data/lib/action_tabler/has_table_action.rb +334 -0
- data/lib/action_tabler/jquery_datatables.rb +16 -0
- data/lib/action_tabler/mapper.rb +21 -0
- data/lib/action_tabler/railtie.rb +43 -0
- data/lib/action_tabler/version.rb +3 -0
- data/lib/action_tabler.rb +31 -0
- data/lib/tasks/table_view_tasks.rake +4 -0
- metadata +144 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# ActionTabler
|
2
|
+
|
3
|
+
ActionTabler provides a drop in table action for your Rails controllers using [DataTables](http://www.datatables.net/).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
1. Add to your Gemfile:
|
8
|
+
|
9
|
+
gem 'action_tabler'
|
10
|
+
|
11
|
+
1. Install the gem:
|
12
|
+
|
13
|
+
bundle install
|
14
|
+
|
15
|
+
1. Include the datatables javascript in application.js:
|
16
|
+
|
17
|
+
//= require action_tabler
|
18
|
+
|
19
|
+
1. Include the datatables css in application.css
|
20
|
+
|
21
|
+
*= require action_tabler
|
22
|
+
|
23
|
+
## Quickstart
|
24
|
+
|
25
|
+
Once you've installed ActionTabler, you can add a fully functional table page to a resource.
|
26
|
+
|
27
|
+
1. Define a table-enabled resourceful route for your controller:
|
28
|
+
|
29
|
+
resources_with_tables :your_thing
|
30
|
+
|
31
|
+
1. Add a declaration to your_thing_controller.rb:
|
32
|
+
|
33
|
+
has_table_action :created_at, :title
|
34
|
+
|
35
|
+
1. Start your server and navigate to "your_thing/table"
|
36
|
+
|
37
|
+
## Configuration
|
38
|
+
|
39
|
+
The following options can be configured with a Rails initializer:
|
40
|
+
|
41
|
+
- `action_tabler_columns`: Array of column specifications. See complete documentation below. Default is nil.
|
42
|
+
- `action_tabler_table_class`: Table html class. Default is nil.
|
43
|
+
- `action_tabler_auto_width`: Datatables auto width setting. Default is true.
|
44
|
+
- `action_tabler_action`: The controller action name for a table. Default is "table".
|
45
|
+
- `action_tabler_auto_type`: Automatically populate datatables column types based on Rails column introspection. Default is true.
|
46
|
+
- `action_tabler_pass_params`: Use request paramters associated with the table resource (eg. "[customers]last_name=Smith") to pre-filter the table data. Default is false, in a trade off of less magic for more security.
|
47
|
+
- `action_tabler_table_options`: Additional DataTables table options, features and callbacks. See the has_table_action :table_options documentation below. Default is empty.
|
48
|
+
|
49
|
+
All of these options can be overridden by the `has_table_action` or `action_tabler_options` declarations.
|
50
|
+
|
51
|
+
## `has_table_action(columns, opts)`
|
52
|
+
|
53
|
+
The `has_table_action` declaration will add a table display action to a controller.
|
54
|
+
|
55
|
+
### columns
|
56
|
+
|
57
|
+
The column parameter describes what will be displayed in your table.
|
58
|
+
|
59
|
+
It is either an array or the symbol `:auto`.
|
60
|
+
|
61
|
+
When :auto, ActionTabler will use reflection to display all of the resource's columns in the table it generates. Use of this option is strong discouraged, but can be used to just make somthing happen, even if it happens insecurely.
|
62
|
+
|
63
|
+
An array will define a list of columns to display.
|
64
|
+
|
65
|
+
A string or symbol in an array will add the corresponding model attribute or method using the default column options.
|
66
|
+
|
67
|
+
You can customize a particular column's options by passing a hash. Each hash can or should have the values below (DataTables equivalents are given in parenthases):
|
68
|
+
|
69
|
+
- `name`: The attribute name. This can be a relationship attribute. For example, if you have an order which belongs to a customer which has a name attribute, you can specify "customer.name". (`mDataProp` and `sName`) *Required.*
|
70
|
+
- `label`: The table column heading for this attribute. Default is the attribute name will be titleized. (`sName`)
|
71
|
+
- `searchable`: Include this column in search box calls. Default is true. (`bSearchable`)
|
72
|
+
- `sortable`: Provide sort controls for this column. Default is true. (`bSortable`)
|
73
|
+
|
74
|
+
Options not listed above will be passed through to DataTables, so that you can access options like `sClass`, `sWidth`, or `sVisible`. For the special handling of the sType column, see the `:auto_type` option below. For more on the special handling of DataTables `fn` or `m` options see the "Datatables fn and m Options" below.
|
75
|
+
|
76
|
+
You can learn more about DataTable column options in the [DataTables Column Usage documentation](http://www.datatables.net/usage/columns).
|
77
|
+
|
78
|
+
This parameter can either be passed as the first argument or as a block. For example:
|
79
|
+
|
80
|
+
has_table_action [:first_name, :last_name], :pass_params => true
|
81
|
+
|
82
|
+
or
|
83
|
+
|
84
|
+
has_table_action(:pass_params => true) do
|
85
|
+
column :title
|
86
|
+
column :author,
|
87
|
+
column :created_at, :label => "Entered", :searchable => false
|
88
|
+
end
|
89
|
+
|
90
|
+
### :action option
|
91
|
+
|
92
|
+
Unless specified otherwise in your Rails configuration, ActionTabler assigns it's table display method to a method called "table." You can override this with the action option, with something like "index," for example.
|
93
|
+
|
94
|
+
### :auto_type option
|
95
|
+
|
96
|
+
Specify whether to populate your column definitions with DataTable's data types using Rails reflections. This will not override any sType speficications you manually configure. Default is true unless otherwise configured.
|
97
|
+
|
98
|
+
### :pass_params option
|
99
|
+
|
100
|
+
Specifies whether to use paramters associated with the table resource to pre-filter the table data.
|
101
|
+
|
102
|
+
### :class_name option
|
103
|
+
|
104
|
+
ActionTabler likes resourceful routes, so it will guess the model from the controller name. You can override this with the class_name option.
|
105
|
+
|
106
|
+
### :table_class option
|
107
|
+
|
108
|
+
This specifies the html class(es) for your table.
|
109
|
+
|
110
|
+
### :table_options option
|
111
|
+
|
112
|
+
You can specify a hash of additional DataTables options, features and callbacks. This will be added to or override your action_tabler_table_options configuration. See "Datatables fn and m Options" below for more on the special handling of DataTables `fn` or `m` options. Please note: you cannot override overriding such options as `bProcessing`, `bServerSide`, `sAjaxSource`, `aoColumnDefs`, or `fnServerParams` could have unintended consequences.
|
113
|
+
|
114
|
+
See the DataTables web site for more about DataTables [Options](http://www.datatables.net/usage/options), [Features](http://www.datatables.net/usage/features), and [Callbacks](http://www.datatables.net/usage/callbacks).
|
115
|
+
|
116
|
+
## Datatables `fn` and `m` Options
|
117
|
+
|
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
|
+
|
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.
|
122
|
+
- Proc: a Proc which will passed the current column definition hash.
|
123
|
+
|
124
|
+
## Running Tests
|
125
|
+
|
126
|
+
$ bundle install
|
127
|
+
$ rspec spec
|
128
|
+
|
129
|
+
## Credits
|
130
|
+
|
131
|
+
Copyright (c) 2013 Larry Halff, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ActionTabler'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require dataTables/jquery.dataTables
|
@@ -0,0 +1 @@
|
|
1
|
+
,
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<table cellpadding="0" cellspacing="0" border="0"<% if @table_class %> class="@table_class"<% end %> id="<%= @table_id %>">
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<% for column in @table_columns do %>
|
5
|
+
<th><%= column[:label] %></th>
|
6
|
+
<% end %>
|
7
|
+
</tr>
|
8
|
+
</thead>
|
9
|
+
<tbody>
|
10
|
+
<tr>
|
11
|
+
<td colspan="5" class="dataTables_empty">Loading data from server</td>
|
12
|
+
</tr>
|
13
|
+
</tbody>
|
14
|
+
</table>
|
15
|
+
|
16
|
+
<script type="text/javascript" charset="utf-8">
|
17
|
+
$(document).ready(function() {
|
18
|
+
$('#<%= @table_id %>').dataTable( <%= render_datatables_table_definitions.html_safe %> );
|
19
|
+
} );
|
20
|
+
</script>
|
File without changes
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -0,0 +1,334 @@
|
|
1
|
+
module ActionTabler
|
2
|
+
module HasTableAction
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
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
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# 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] || {})
|
56
|
+
|
57
|
+
include DeclaredInstanceMethods
|
58
|
+
|
59
|
+
# Define the table action method
|
60
|
+
define_method(action_tabler_action) do
|
61
|
+
action_tabler
|
62
|
+
end
|
63
|
+
|
64
|
+
# Make the column name formaters available in views
|
65
|
+
helper_method :column_name_for_json, :column_name_from_json, :render_datatables_table_definitions
|
66
|
+
end # has_table_action
|
67
|
+
|
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
|
+
end # ClassMethods
|
99
|
+
|
100
|
+
module DeclaredInstanceMethods
|
101
|
+
|
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
|
+
private
|
121
|
+
|
122
|
+
# Main table view action
|
123
|
+
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
|
+
respond_to do |format|
|
134
|
+
format.html {action_tabler_for_html}
|
135
|
+
format.json {action_tabler_for_json}
|
136
|
+
end # respond_to
|
137
|
+
end # datatable_index
|
138
|
+
|
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
|
+
# Discover relation model name
|
236
|
+
reflection = model.reflect_on_association(name.split(".")[0].to_sym)
|
237
|
+
# Recurse with realtion model and name
|
238
|
+
tabler_column_type_for(name.gsub("#{names[0]}.", ""), reflection.klass)
|
239
|
+
else
|
240
|
+
# Look up and return the Datatables column type
|
241
|
+
ActionTabler::JqueryDatatables.column_type_for(model.columns_hash[name].class)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
###
|
246
|
+
# Data Rendering
|
247
|
+
###
|
248
|
+
|
249
|
+
# Render the table data
|
250
|
+
def action_tabler_for_json
|
251
|
+
# Select the requested records
|
252
|
+
@records = @table_model.where(@table_parameters).
|
253
|
+
where(action_tabler_global_conditions).
|
254
|
+
where(action_tabler_column_conditions).
|
255
|
+
limit(params[:iDisplayLength]).
|
256
|
+
offset(params[:iDisplayStart]).
|
257
|
+
order(action_tabler_sort_order)
|
258
|
+
# Count the total records available
|
259
|
+
records_count = @table_model.where(@table_parameters).
|
260
|
+
where(action_tabler_global_conditions).
|
261
|
+
where(action_tabler_column_conditions).
|
262
|
+
count
|
263
|
+
# Find out total records, including those not found by a search specification
|
264
|
+
total_count = @table_model.where(@table_parameters).count
|
265
|
+
|
266
|
+
@column_names = []
|
267
|
+
|
268
|
+
# Build a hash with json safe column names
|
269
|
+
@records = @records.inject([]) do |result, record|
|
270
|
+
result << action_tabler_columns.inject([]) do |this, column|
|
271
|
+
this << eval("record.#{column[:name]}")
|
272
|
+
@column_names << column[:name].to_s
|
273
|
+
this
|
274
|
+
end
|
275
|
+
result
|
276
|
+
end
|
277
|
+
|
278
|
+
# Render the data as json
|
279
|
+
render :json => { :iTotalRecords => total_count,
|
280
|
+
:iTotalDisplayRecords => records_count,
|
281
|
+
:sNames => @column_names,
|
282
|
+
:aaData => @records,
|
283
|
+
:sEcho => params[:sEcho].to_i }
|
284
|
+
end # datatable_json_index
|
285
|
+
|
286
|
+
# Calculate global finder were clause
|
287
|
+
def action_tabler_global_conditions
|
288
|
+
# Check to see if there's a search parameter
|
289
|
+
unless params[:sSearch].to_s.empty?
|
290
|
+
# Build a LIKE condition string with searchable fields
|
291
|
+
# NOTE: This ignores client-side specified searchable fields
|
292
|
+
search_string = action_tabler_searchable_columns.collect {|c| "#{column[:name]} LIKE :keyword"}.join(" OR ")
|
293
|
+
|
294
|
+
# Assemble the condition string along with the search parameter
|
295
|
+
[search_string, {:keyword => "%#{params[:sSearch].to_s}%"}]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# Calculate where clause for individual column filtering
|
300
|
+
def action_tabler_column_conditions
|
301
|
+
action_tabler_searchable_columns.inject({}) do |result, column|
|
302
|
+
search_string = params["sSearch_#{action_tabler_columns.index(column)}"].to_s
|
303
|
+
unless search_string.empty?
|
304
|
+
result[column[:name]] = search_string
|
305
|
+
end
|
306
|
+
result
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# List searchable columns
|
311
|
+
def action_tabler_searchable_columns
|
312
|
+
action_tabler_columns.select{|column| column[:searchable] != false}
|
313
|
+
end
|
314
|
+
|
315
|
+
# Returns the finder order clause
|
316
|
+
def action_tabler_sort_order
|
317
|
+
sort_conditions = params.inject([]) do |result, (k, v)|
|
318
|
+
# Find all of the parameters which start with iSortCol
|
319
|
+
if k.match(/iSortCol_(\d+)/) && i = k.match(/iSortCol_(\d+)/)[1]
|
320
|
+
# Add this sort condition to the temporary array
|
321
|
+
if action_tabler_columns[v.to_i][:sortable] != false
|
322
|
+
result << "#{action_tabler_columns[v.to_i][:name]} #{params['sSortDir_' + i.to_s]}"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
result
|
326
|
+
end
|
327
|
+
|
328
|
+
# Join the array into a sort string
|
329
|
+
sort_conditions.join(", ").strip
|
330
|
+
end
|
331
|
+
|
332
|
+
end # InstanceMethods
|
333
|
+
end #AbstractController
|
334
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActionTabler
|
2
|
+
module Routing
|
3
|
+
module Mapper
|
4
|
+
|
5
|
+
# Add a routing mapper for a list of resourceful controllers with tables
|
6
|
+
def resources_with_tables *args
|
7
|
+
resources *args do
|
8
|
+
get 'table', :on => :collection
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add a routing mapper for a single resourceful controller with tables
|
13
|
+
def resource_with_tables *args
|
14
|
+
resource *args do
|
15
|
+
get 'table', :on => :collection
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActionTabler
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
end
|
4
|
+
|
5
|
+
class ActionTablerRailtie < Rails::Railtie
|
6
|
+
railtie_name :action_tabler
|
7
|
+
|
8
|
+
initializer "action_tabler" do
|
9
|
+
AbstractController::Base.send :include, ActionTabler::HasTableAction
|
10
|
+
ActionDispatch::Routing::Mapper.send :include, ActionTabler::Routing::Mapper
|
11
|
+
end
|
12
|
+
|
13
|
+
config.to_prepare do
|
14
|
+
ActionTablerRailtie.initialize_configuration(Rails.configuration)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize_configuration(config)
|
18
|
+
|
19
|
+
# Check and set default column definitions
|
20
|
+
if config.respond_to?(:action_tabler_columns)
|
21
|
+
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
|
25
|
+
else
|
26
|
+
raise ArgumentError, "config.action_tabler_columns expected Symbol, Array, or Proc (got #{config.action_tabler_attributes.class.name})"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
AbstractController::Base.action_tabler_columns = []
|
30
|
+
end
|
31
|
+
|
32
|
+
# 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 : {}
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'action_tabler/jquery_datatables'
|
2
|
+
require 'action_tabler/has_table_action'
|
3
|
+
require 'action_tabler/mapper'
|
4
|
+
require 'action_tabler/railtie' if defined?(Rails)
|
5
|
+
|
6
|
+
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
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: action_tabler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- lhalff
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2013-06-05 00:00:00 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: rails
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 21
|
28
|
+
segments:
|
29
|
+
- 3
|
30
|
+
- 2
|
31
|
+
- 13
|
32
|
+
version: 3.2.13
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: jquery-datatables-rails
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 63
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 11
|
47
|
+
- 2
|
48
|
+
version: 1.11.2
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: sqlite3
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: rspec-rails
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 57
|
74
|
+
segments:
|
75
|
+
- 2
|
76
|
+
- 13
|
77
|
+
- 1
|
78
|
+
version: 2.13.1
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
description: A drop in table action for your Rails controllers using DataTables.
|
82
|
+
email:
|
83
|
+
- email@larryhalff.com
|
84
|
+
executables: []
|
85
|
+
|
86
|
+
extensions: []
|
87
|
+
|
88
|
+
extra_rdoc_files: []
|
89
|
+
|
90
|
+
files:
|
91
|
+
- app/assets/javascripts/action_tabler.js
|
92
|
+
- app/assets/stylesheets/action_tabler.css
|
93
|
+
- app/assets/stylesheets/action_tabler_bootstrap.css
|
94
|
+
- app/views/action_tabler/_comma_spacer.html.erb
|
95
|
+
- app/views/action_tabler/_table.html.erb
|
96
|
+
- app/views/action_tabler/_table_footer.html.erb
|
97
|
+
- app/views/action_tabler/_table_header.html.erb
|
98
|
+
- app/views/action_tabler/table.html.erb
|
99
|
+
- lib/action_tabler/column_type_for.rb
|
100
|
+
- lib/action_tabler/has_table_action.rb
|
101
|
+
- lib/action_tabler/jquery_datatables.rb
|
102
|
+
- lib/action_tabler/mapper.rb
|
103
|
+
- lib/action_tabler/railtie.rb
|
104
|
+
- lib/action_tabler/version.rb
|
105
|
+
- lib/action_tabler.rb
|
106
|
+
- lib/tasks/table_view_tasks.rake
|
107
|
+
- MIT-LICENSE
|
108
|
+
- Rakefile
|
109
|
+
- README.md
|
110
|
+
homepage: https://github.com/lhalff/action_tabler
|
111
|
+
licenses: []
|
112
|
+
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
hash: 3
|
124
|
+
segments:
|
125
|
+
- 0
|
126
|
+
version: "0"
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 3
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
requirements: []
|
137
|
+
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 1.8.25
|
140
|
+
signing_key:
|
141
|
+
specification_version: 3
|
142
|
+
summary: has_table_index mixin for ActionController
|
143
|
+
test_files: []
|
144
|
+
|