datatablesnet 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/Gemfile +5 -0
- data/datatablesnet.gemspec +21 -0
- data/lib/datatablesnet/_table.html.haml +43 -0
- data/lib/datatablesnet/datatable.rb +310 -0
- data/lib/datatablesnet/hash_sql.rb +85 -0
- data/lib/datatablesnet/railtie.rb +12 -0
- data/lib/datatablesnet/types.rb +34 -0
- data/lib/datatablesnet/version.rb +3 -0
- data/lib/datatablesnet.rb +10 -0
- metadata +73 -0
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "datatablesnet/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "datatablesnet"
|
7
|
+
s.version = Datatablesnet::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.summary = "Datatables.net component for rails"
|
10
|
+
s.email = "mfields106@gmail.com"
|
11
|
+
s.homepage = "https://github.com/IslandPort/datatablesnet"
|
12
|
+
s.description = "Component abstraction for datatables.net"
|
13
|
+
s.authors = ['Matt Fields']
|
14
|
+
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
-options = config[:options]
|
2
|
+
|
3
|
+
:javascript
|
4
|
+
$(document).ready(function(){
|
5
|
+
$('##{table_id}').dataTable(#{config[:table_options].to_json});
|
6
|
+
if(#{options[:toolbar].present? or options[:toolbar_external]}){
|
7
|
+
$('div.toolbar').html($('##{table_id}_toolbar').html());
|
8
|
+
}
|
9
|
+
if(#{options[:width].present?}){
|
10
|
+
$('##{table_id}_wrapper').css('width', '#{options[:width].to_s}');
|
11
|
+
}
|
12
|
+
});
|
13
|
+
|
14
|
+
-if options[:toolbar].present?
|
15
|
+
%div{:id => table_id + "_toolbar", :style => "display:none"}
|
16
|
+
- options[:toolbar].each do |toolbar_item|
|
17
|
+
.toolbarItem
|
18
|
+
-if toolbar_item[:url]
|
19
|
+
=link_to toolbar_item[:text], toolbar_item[:url] , :class=>"btn"
|
20
|
+
-else
|
21
|
+
=toolbar_item[:text]
|
22
|
+
|
23
|
+
%table.display{:id => table_id, :style => "#{options[:width].present? ? 'width:' + options[:width].to_s : 'width:100%!important'}"}
|
24
|
+
%thead
|
25
|
+
- columns.each do |column|
|
26
|
+
%th= column[:label]
|
27
|
+
- if options[:show_actions].to_b
|
28
|
+
%th Actions
|
29
|
+
- if options[:server_side].to_b
|
30
|
+
%th
|
31
|
+
%tbody
|
32
|
+
- unless options[:data_url].present?
|
33
|
+
- rows.each do |row|
|
34
|
+
%tr
|
35
|
+
- columns.each do |column|
|
36
|
+
%td
|
37
|
+
=datatable_get_column_data(row,column)
|
38
|
+
- if options[:show_actions] == 'true'
|
39
|
+
%td
|
40
|
+
.tableAction= link_to 'Show', row
|
41
|
+
.tableAction= link_to 'Edit', send("edit_#{row.class.to_s.demodulize.underscore}_path",row)
|
42
|
+
.tableAction= link_to 'Destroy', row, :confirm => 'Are you sure?', :method => :delete
|
43
|
+
|
@@ -0,0 +1,310 @@
|
|
1
|
+
require 'datatablesnet/types'
|
2
|
+
|
3
|
+
module Datatable
|
4
|
+
|
5
|
+
class UrlHelper
|
6
|
+
include Rails.application.routes.url_helpers
|
7
|
+
#default_url_options[:routing_type] = :path
|
8
|
+
|
9
|
+
def url_for(options = {})
|
10
|
+
options ||= {}
|
11
|
+
url = case options
|
12
|
+
when String
|
13
|
+
super
|
14
|
+
when Hash
|
15
|
+
super
|
16
|
+
when :back
|
17
|
+
super
|
18
|
+
else
|
19
|
+
polymorphic_path(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
url
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#Options
|
27
|
+
# :sort_by
|
28
|
+
# :additional_data
|
29
|
+
# :search
|
30
|
+
# :search_label
|
31
|
+
# :processing
|
32
|
+
# :persist_state
|
33
|
+
# :per_page
|
34
|
+
# :no_records_message
|
35
|
+
# :auto_width
|
36
|
+
# :row_callback
|
37
|
+
# :show_actions
|
38
|
+
#Column Options
|
39
|
+
# :name
|
40
|
+
# :label
|
41
|
+
# :render
|
42
|
+
# :format
|
43
|
+
|
44
|
+
module_function
|
45
|
+
|
46
|
+
def template_path
|
47
|
+
path = File.expand_path('..', __FILE__)
|
48
|
+
$:.unshift(path)
|
49
|
+
path
|
50
|
+
end
|
51
|
+
|
52
|
+
def datatable_tag id, columns = [], rows = nil, options = {}
|
53
|
+
options_map = {:sort_by => "aaSorting",
|
54
|
+
:search => "bFilter",
|
55
|
+
:search_label => "sSearch",
|
56
|
+
:processing => "bProcessing",
|
57
|
+
:persist_state => "bSaveState",
|
58
|
+
:per_page => "iDisplayLength",
|
59
|
+
:no_records_message => "sZeroRecords",
|
60
|
+
:auto_width => "bAutoWidth",
|
61
|
+
:dom => "sDom",
|
62
|
+
:data_url => "sAjaxSource",
|
63
|
+
:server_side => "bServerSide",
|
64
|
+
:auto_scroll => "bScrollInfinite",
|
65
|
+
:pagination_type => "sPaginationType",
|
66
|
+
:paginate => "bPaginate",
|
67
|
+
:save_state => "bStateSave"
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
options =
|
72
|
+
{
|
73
|
+
:show_actions => true,
|
74
|
+
:per_page => 25,
|
75
|
+
:toolbar_external => false
|
76
|
+
}.merge(options)
|
77
|
+
|
78
|
+
index = 0
|
79
|
+
columns.each do |column|
|
80
|
+
column[:label] = field_to_label(column[:field]) unless column[:label].present?
|
81
|
+
if options[:data_url].present?
|
82
|
+
options[:data_url] << "?" if column == columns.first
|
83
|
+
options[:data_url] << "column_field_#{index.to_s}=#{column[:field]}"
|
84
|
+
if column[:view_link].present?
|
85
|
+
options[:data_url] << "&column_view_link_#{index.to_s}=#{column[:view_link]}"
|
86
|
+
end
|
87
|
+
options[:data_url] << "&" unless column == columns.last
|
88
|
+
end
|
89
|
+
index += 1
|
90
|
+
end
|
91
|
+
|
92
|
+
if options[:toolbar].present? or options[:toolbar_external]
|
93
|
+
options[:dom]='<"toolbar">lfrtip'
|
94
|
+
end
|
95
|
+
|
96
|
+
table_options = {}
|
97
|
+
options_map.each do |k,v|
|
98
|
+
if options[k].present?
|
99
|
+
table_options[v] = options[k]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
table_options["aoColumns"] = datatable_get_column_defs(options,columns)
|
104
|
+
|
105
|
+
config = {:options => options, :columns =>columns, :table_options => table_options}
|
106
|
+
config.to_json
|
107
|
+
render :file => template_path + "/_table", :locals => { :table_id => id, :columns => columns, :rows => rows, :config => config}
|
108
|
+
end
|
109
|
+
|
110
|
+
def datatable_get_column_defs options, columns
|
111
|
+
column_defs = []
|
112
|
+
column_options_map = {:width => "sWidth",
|
113
|
+
:sortable => "bSortable",
|
114
|
+
:searchable => "bSearchable",
|
115
|
+
:class => "sClass"}
|
116
|
+
|
117
|
+
|
118
|
+
column_index =0
|
119
|
+
columns.each do |column|
|
120
|
+
column_options = {}
|
121
|
+
column_options_map.each do |k,v|
|
122
|
+
if column[k].present?
|
123
|
+
column_options[v] = column[k]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
column_options["fnRender"] = NoEscape.new(options[:render]) if column[:render].present?
|
127
|
+
column_options["fnRender"] = NoEscape.new("function (obj) {return #{column[:format]}(obj.aData[#{column_index}])}") if column[:format].present?
|
128
|
+
if column[:view_link].present? and options[:server_side]
|
129
|
+
column_options["fnRender"] = NoEscape.new("function (obj) {return '<a href = ' + obj.aData[#{columns.length}]['urls']['#{column[:field]}'] + '>' + obj.aData[#{column_index}] + '</a>'}")
|
130
|
+
end
|
131
|
+
|
132
|
+
unless column_options.empty?
|
133
|
+
column_defs << column_options
|
134
|
+
else
|
135
|
+
column_defs << nil
|
136
|
+
end
|
137
|
+
column_index+=1
|
138
|
+
end
|
139
|
+
|
140
|
+
if options[:show_actions]
|
141
|
+
column_defs << nil
|
142
|
+
end
|
143
|
+
|
144
|
+
if options[:server_side]
|
145
|
+
column_defs << {"bVisible" => false}
|
146
|
+
end
|
147
|
+
|
148
|
+
return column_defs
|
149
|
+
end
|
150
|
+
|
151
|
+
def get_field_data obj, field
|
152
|
+
attrs = field.split('.')
|
153
|
+
attrs.each do |attr|
|
154
|
+
if obj
|
155
|
+
obj = obj.send attr
|
156
|
+
else
|
157
|
+
return ""
|
158
|
+
end
|
159
|
+
end
|
160
|
+
return obj
|
161
|
+
end
|
162
|
+
|
163
|
+
def datatable_get_column_data row, column
|
164
|
+
obj = get_field_data(row, column[:field])
|
165
|
+
|
166
|
+
if column[:view_link].present?
|
167
|
+
if column[:view_link] == "."
|
168
|
+
return link_to(obj, row)
|
169
|
+
else
|
170
|
+
return link_to(obj, row.send(column[:view_link]))
|
171
|
+
end
|
172
|
+
else
|
173
|
+
return obj
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def field_to_label(field)
|
178
|
+
label = field.gsub(/[_.]/, " ")
|
179
|
+
label.to_s.gsub(/\b\w/){$&.upcase}
|
180
|
+
end
|
181
|
+
|
182
|
+
def parse_params params
|
183
|
+
grid_options = {}
|
184
|
+
columns = []
|
185
|
+
order_by = {}
|
186
|
+
filter_by = {}
|
187
|
+
(0..params[:iColumns].to_i-2).each do |index|
|
188
|
+
column = {}
|
189
|
+
column[:field] = params["column_field_#{index}"]
|
190
|
+
column[:searchable] = params["bSearchable_#{index}"].to_b
|
191
|
+
column[:sortable] = params["bSortable_#{index}"].to_b
|
192
|
+
column[:index] = index
|
193
|
+
if params["column_view_link_#{index}"].present?
|
194
|
+
column[:view_link] = params["column_view_link_#{index}"]
|
195
|
+
end
|
196
|
+
columns << column
|
197
|
+
if params["iSortCol_#{index}"].present?
|
198
|
+
order_column_index = params["iSortCol_#{index}"]
|
199
|
+
order_column = params["column_field_#{order_column_index}"]
|
200
|
+
order_column_order = params["sSortDir_#{index}"] || "DESC"
|
201
|
+
order_by[order_column] = order_column_order
|
202
|
+
end
|
203
|
+
if params["sSearch_#{index}"].present?
|
204
|
+
filter_by[column[:field]] = params["sSearch_#{index}"]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
grid_options[:columns] = columns
|
209
|
+
grid_options[:order_by] = order_by
|
210
|
+
grid_options[:filter_by] = filter_by
|
211
|
+
grid_options[:page] = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
|
212
|
+
grid_options[:per_page] = params[:iDisplayLength]
|
213
|
+
if params["sSearch"].present?
|
214
|
+
grid_options[:search] = params["sSearch"]
|
215
|
+
end
|
216
|
+
|
217
|
+
grid_options
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
def find(klass, params={}, options = {})
|
222
|
+
field_filter_where = {}
|
223
|
+
all_filter_where = {}
|
224
|
+
|
225
|
+
grid_options = parse_params params
|
226
|
+
|
227
|
+
|
228
|
+
options[:page] = grid_options[:page]
|
229
|
+
options[:per_page] = grid_options[:per_page]
|
230
|
+
|
231
|
+
# Build order by
|
232
|
+
grid_options[:order_by].each do |column, order|
|
233
|
+
if options[:order].present?
|
234
|
+
options[:order] << ", "
|
235
|
+
else
|
236
|
+
options[:order] = ""
|
237
|
+
end
|
238
|
+
options[:order] << "#{column} #{order}"
|
239
|
+
end
|
240
|
+
|
241
|
+
# Build filter by
|
242
|
+
grid_options[:filter_by].each do |column, value|
|
243
|
+
field_filter_where[column] = value
|
244
|
+
end
|
245
|
+
|
246
|
+
# Search all searchable columns
|
247
|
+
if grid_options[:search].present?
|
248
|
+
grid_options[:columns].each do |column|
|
249
|
+
if column[:searchable].to_b
|
250
|
+
all_filter_where[column[:field]] = grid_options[:search]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
if !field_filter_where.empty? or !all_filter_where.empty?
|
256
|
+
options[:conditions] = [field_filter_where.sql_like, all_filter_where.sql_or.sql_like].sql_and.sql_where
|
257
|
+
end
|
258
|
+
|
259
|
+
puts options[:conditions]
|
260
|
+
|
261
|
+
rows = klass.paginate options
|
262
|
+
|
263
|
+
objects = []
|
264
|
+
rows.each do |row|
|
265
|
+
object = []
|
266
|
+
grid_options[:columns].each do |column|
|
267
|
+
object << get_field_data(row, column[:field])
|
268
|
+
end
|
269
|
+
|
270
|
+
meta = build_row_meta row, grid_options
|
271
|
+
object << meta
|
272
|
+
objects << object
|
273
|
+
end
|
274
|
+
|
275
|
+
total_records = klass.count
|
276
|
+
if options[:conditions].present?
|
277
|
+
klass.count(:conditions => options[:conditions])
|
278
|
+
else
|
279
|
+
total_display_records = total_records
|
280
|
+
end
|
281
|
+
json_data = {:sEcho => params[:sEcho],
|
282
|
+
:iTotalRecords => total_records,
|
283
|
+
:iTotalDisplayRecords => total_display_records,
|
284
|
+
:aaData => objects
|
285
|
+
}
|
286
|
+
return json_data
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
def build_row_meta row, grid_options
|
291
|
+
url_helper = UrlHelper.new
|
292
|
+
meta={}
|
293
|
+
meta[:urls] = {}
|
294
|
+
grid_options[:columns].each do |column|
|
295
|
+
if column[:view_link].present?
|
296
|
+
view_link = column[:view_link]
|
297
|
+
if view_link == "."
|
298
|
+
url = url_helper.url_for(row)
|
299
|
+
else
|
300
|
+
url = url_helper.url_for(row.send(view_link))
|
301
|
+
end
|
302
|
+
meta[:urls][column[:field]] = url
|
303
|
+
end
|
304
|
+
end
|
305
|
+
return meta
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module HashSql
|
4
|
+
|
5
|
+
def self.included(klass)
|
6
|
+
klass.send :include, InstanceMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
|
11
|
+
attr_accessor :sql_operator
|
12
|
+
attr_accessor :sql_comparator
|
13
|
+
|
14
|
+
def sql_where
|
15
|
+
if self.instance_of?(Hash)
|
16
|
+
build_where
|
17
|
+
else
|
18
|
+
combine_wheres
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def sql_and
|
23
|
+
self.sql_operator = "and"
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
|
27
|
+
def sql_or
|
28
|
+
self.sql_operator = "or"
|
29
|
+
return self
|
30
|
+
end
|
31
|
+
|
32
|
+
def sql_like
|
33
|
+
self.sql_comparator = "like"
|
34
|
+
return self
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def build_where
|
41
|
+
values = []
|
42
|
+
where_string = ""
|
43
|
+
self.each do |name, value|
|
44
|
+
if where_string != ""
|
45
|
+
where_string << " #{sql_operator ? sql_operator : 'and'} "
|
46
|
+
end
|
47
|
+
|
48
|
+
if self.sql_comparator = "like"
|
49
|
+
where_string << "#{name} LIKE ?"
|
50
|
+
values << '%' + value + '%'
|
51
|
+
else
|
52
|
+
where_string << "#{name} = ?"
|
53
|
+
values << value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
where = [where_string] + values
|
57
|
+
return where
|
58
|
+
end
|
59
|
+
|
60
|
+
def combine_wheres
|
61
|
+
values = []
|
62
|
+
where_string = ""
|
63
|
+
self.each do |where_hash|
|
64
|
+
unless where_hash.empty?
|
65
|
+
where = where_hash.sql_where
|
66
|
+
if where_string != ""
|
67
|
+
where_string << " and "
|
68
|
+
end
|
69
|
+
|
70
|
+
where_string << "(#{where[0]})"
|
71
|
+
|
72
|
+
values += where[1..-1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
[where_string] + values
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
[Array, Hash].each do |klass|
|
82
|
+
klass.class_eval do
|
83
|
+
include HashSql
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
class NoEscape
|
3
|
+
def as_json(options = nil) self end #:nodoc:
|
4
|
+
def encode_json(encoder) to_s end #:nodoc:
|
5
|
+
|
6
|
+
def initialize text
|
7
|
+
@text = text
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
@text
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
module ToBoolean
|
17
|
+
def self.included(klass)
|
18
|
+
klass.send :include, InstanceMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
def to_b
|
24
|
+
string = self
|
25
|
+
return true if string == true || string =~ (/(true|t|yes|y|1)$/i)
|
26
|
+
return false if string == false || string.nil? || string =~ (/(false|f|no|n|0)$/i)
|
27
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{string}\"")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Object.class_eval do
|
33
|
+
include ToBoolean
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: datatablesnet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: "1.0"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Matt Fields
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-07-30 00:00:00 Z
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: Component abstraction for datatables.net
|
21
|
+
email: mfields106@gmail.com
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files: []
|
27
|
+
|
28
|
+
files:
|
29
|
+
- .gitignore
|
30
|
+
- Gemfile
|
31
|
+
- datatablesnet.gemspec
|
32
|
+
- lib/datatablesnet.rb
|
33
|
+
- lib/datatablesnet/_table.html.haml
|
34
|
+
- lib/datatablesnet/datatable.rb
|
35
|
+
- lib/datatablesnet/hash_sql.rb
|
36
|
+
- lib/datatablesnet/railtie.rb
|
37
|
+
- lib/datatablesnet/types.rb
|
38
|
+
- lib/datatablesnet/version.rb
|
39
|
+
homepage: https://github.com/IslandPort/datatablesnet
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
hash: 3
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.7.2
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Datatables.net component for rails
|
72
|
+
test_files: []
|
73
|
+
|