data_tables 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ module DataTablesHelper
2
+ def datatables(source, opts = {})
3
+
4
+ options = opts[:jquery] ? opts[:jquery].dup : {}
5
+ options[:bJQueryUI] = true unless options.has_key?(:bJQueryUI)
6
+ options[:bProcessing] = true unless options.has_key?(:bProcessing)
7
+ options[:bServerSide] = true unless options.has_key?(:bServerSide)
8
+ options[:bAutoWidth] = false unless options.has_key?(:bAutoWidth)
9
+ options[:bStateSave] = true unless options.has_key?(:bStateSave)
10
+ options[:oColVis] ||= {}
11
+ options[:oColVis][:aiExclude] ||= []
12
+ unless options[:oColVis][:aiExclude].include?(0)
13
+ options[:oColVis][:aiExclude].unshift(0)
14
+ end
15
+
16
+ options[:fnInitComplete] ||= "function() {
17
+ if (eval('typeof ' + initDatatablesTable) == 'function') {
18
+ initDatatablesTable('#{source}');
19
+ }
20
+ }"
21
+
22
+ sdom = '<"#datatables_search_hint">lfrtip'
23
+ sdom = "C<\"clear\">" + sdom if options[:oColVis]
24
+ sdom = 'T' + sdom if options[:oTableTools]
25
+ options[:sDom] ||= sdom
26
+
27
+ datatable = controller.datatable_source(source)
28
+ options[:sAjaxSource] = method("#{datatable[:action]}_url".to_sym).call
29
+ columns = datatable[:attrs].keys.collect { |a| "<th>#{a}</th>" }.join
30
+
31
+ index = 0
32
+ targets = datatable[:attrs].inject([]) do |memo, (column, searchable)|
33
+ memo << index unless searchable
34
+ index += 1
35
+ memo
36
+ end
37
+ options[:aoColumnDefs] ||= []
38
+ options[:aoColumnDefs].unshift({
39
+ :aTargets => targets,
40
+ :bSearchable => false,
41
+ :bSortable => false
42
+ })
43
+
44
+ if options[:html]
45
+ html_opts = options[:html].collect { |k,v| "#{k}=\"#{v}\"" }.join(' ')
46
+ end
47
+ pad_ao_columns(options, datatable[:attrs].keys.size)
48
+
49
+ table_header = "<tr>#{columns}</tr>"
50
+ html = "
51
+ <script>
52
+ $(document).ready(function() {
53
+ var oTable = $('##{datatable[:action]}').dataTable({
54
+ #{datatables_option_string(options)}
55
+ });
56
+ $('tfoot input').keyup( function () {
57
+ /* Filter on the column (the index) of this element */
58
+ oTable.fnFilter( this.value, $('tfoot input').index(this) );
59
+ } );
60
+
61
+ });
62
+ </script>
63
+ <table id=\"#{datatable[:action]}\" #{html_opts}>
64
+ <thead>
65
+ #{table_header}
66
+ </thead>
67
+ <tbody>
68
+ </tbody>
69
+ </table>
70
+ "
71
+ return raw(html)
72
+ end
73
+ end
74
+
75
+ def datatables_option_string(options, indent = 4)
76
+ arr = []
77
+ options.each do |key, value|
78
+ if value.is_a?(String) && value[0..7] != "function"
79
+ arr << "#{' ' * indent}#{key}: '#{value}'"
80
+ elsif value.is_a?(Array)
81
+ indent += 2
82
+ item_arr = []
83
+ value.each do |item|
84
+ if item.is_a?(Hash)
85
+ str = "#{' ' * indent}{\n"
86
+ str += "#{datatables_option_string(item, indent + 2)}\n"
87
+ str += "#{' ' * indent}}"
88
+ item_arr << str
89
+ elsif item.is_a?(String) && item[0..7] != "function"
90
+ item_arr << "#{' ' * indent}'#{item}'"
91
+ else
92
+ item_arr << "#{' ' * indent}#{item}"
93
+ end
94
+ end
95
+ indent -= 2
96
+ arr << "#{' ' * indent}#{key}: [\n#{item_arr.join(",\n")}\n#{' ' * indent}]"
97
+ elsif value.is_a?(Hash)
98
+ str = "#{' ' * indent}#{key}: {\n"
99
+ str += "#{datatables_option_string(value, indent + 2)}\n"
100
+ str += "#{' ' * indent}}"
101
+ arr << str
102
+ else
103
+ arr << "#{' ' * indent}#{key}: #{value}"
104
+ end
105
+ end
106
+
107
+ arr.join(",\n")
108
+ end
109
+
110
+ def pad_ao_columns(options, count)
111
+ return unless options[:aoColumns]
112
+
113
+ (count - options[:aoColumns].size).times do
114
+ options[:aoColumns] << 'null'
115
+ end
116
+ end
@@ -0,0 +1,210 @@
1
+ require 'data_tables/data_tables_helper'
2
+ module DataTablesController
3
+ def self.included(cls)
4
+ cls.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def datatables_source(action, model, *attrs)
9
+ modelCls = Kernel.const_get(model.to_s.split("_").collect(&:capitalize).join)
10
+ modelAttrs = nil
11
+ if modelCls < Ohm::Model
12
+ modelAttrs = Hash[*modelCls.new.attributes.collect { |v| [v.to_s, nil] }.flatten]
13
+ else
14
+ modelAttrs = modelCls.new.attributes
15
+ end
16
+ columns = []
17
+ modelAttrs.each_key { |k| columns << k }
18
+
19
+ options = {}
20
+ attrs.each do |option|
21
+ option.each { |k,v| options[k] = v }
22
+ end
23
+
24
+ # override columns
25
+ columns = options_to_columns(options) if options[:columns]
26
+
27
+ # define columns so they are accessible from the helper
28
+ define_columns(modelCls, columns, action)
29
+
30
+ # define method that returns the data for the table
31
+ define_datatables_action(self, action, modelCls, columns, options)
32
+ end
33
+
34
+ # named_scope is a combination table that include everything shown in UI.
35
+ # except is the codition used for Ohm's except method, it should be key-value format,
36
+ # such as [['name', 'bluesocket'],['id','1']].
37
+ def define_datatables_action(controller, action, modelCls, columns, options = {})
38
+ conditions = options[:conditions] || []
39
+ scope = options[:scope] || :domain
40
+ named_scope = options[:named_scope]
41
+ except = options[:except]
42
+
43
+ if modelCls < Ohm::Model
44
+ define_method action.to_sym do
45
+ if scope == :domain
46
+ domain = ActiveRecord::Base.connection.schema_search_path.to_s.split(",")[0]
47
+ return if domain.nil?
48
+ end
49
+ search_condition = params[:sSearch].blank? ? nil : params[:sSearch].to_s
50
+ records = scope == :domain ? modelCls.find(:domain => domain) : modelCls.all
51
+ if except
52
+ except.each do |f|
53
+ records = records.except(f[0].to_sym => f[1])
54
+ end
55
+ end
56
+ total_records = records.size
57
+ sort_column = params[:iSortCol_0].to_i
58
+ sort_column = 1 if sort_column == 0
59
+ current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0) + 1
60
+ objects = nil
61
+ if search_condition.nil?
62
+ objects = records.sort_by(columns[sort_column][:name].to_sym, :order=>"ALPHA " + params[:sSortDir_0].capitalize, :limit=>params[:iDisplayLength].to_i, :start=>(params[:iDisplayStart].to_i))
63
+ total_display_records = total_records
64
+ else
65
+ options = {}
66
+ domain_id = domain.split("_")[1].to_i if scope == :domain
67
+ options[:domain] = domain_id .. domain_id if scope == :domain
68
+ options[:fuzzy] = {columns[sort_column][:name].to_sym => search_condition}
69
+ objects = Lunar.search(modelCls, options)
70
+ total_display_records = objects.size
71
+ objects = objects.sort(:by => columns[sort_column][:name].to_sym, :order=>"ALPHA " + params[:sSortDir_0].capitalize, :limit=>params[:iDisplayLength].to_i, :start=>(params[:iDisplayStart].to_i))
72
+ end
73
+ data = objects.collect do |instance|
74
+ columns.collect { |column| datatables_instance_get_value(instance, column) }
75
+ end
76
+ render :text => {:iTotalRecords => total_records,
77
+ :iTotalDisplayRecords => total_display_records,
78
+ :aaData => data,
79
+ :sEcho => params[:sEcho].to_i}.to_json
80
+ end
81
+ else
82
+ # add_search_option will determine whether the search text is empty or not
83
+ init_conditions = conditions.clone
84
+ add_search_option = false
85
+ define_method action.to_sym do
86
+ condition_local = ''
87
+ unless params[:sSearch].blank?
88
+ sort_column_id = params[:iSortCol_0].to_i
89
+ sort_column_id = 1 if sort_column_id == 0
90
+ sort_column = columns[sort_column_id]
91
+ if sort_column && sort_column.has_key?(:attribute)
92
+ condstr = params[:sSearch].gsub(/_/, '\\\\_').gsub(/%/, '\\\\%')
93
+ condition_local = "(text(#{sort_column[:name]}) ILIKE '#{condstr}%')"
94
+ end
95
+ end
96
+
97
+ # We just need one conditions string for search at a time. Every time we input
98
+ # something else in the search bar we will pop the previous search condition
99
+ # string and push the new string.
100
+ if condition_local != ''
101
+ if add_search_option == false
102
+ conditions << condition_local
103
+ add_search_option = true
104
+ else
105
+ if conditions != []
106
+ conditions.pop
107
+ conditions << condition_local
108
+ end
109
+ end
110
+ else
111
+ if add_search_option == true
112
+ if conditions != []
113
+ conditions.pop
114
+ add_search_option = false
115
+ end
116
+ end
117
+ end
118
+
119
+ if named_scope
120
+ total_records = modelCls.send(named_scope).count :conditions => init_conditions.join(" AND ")
121
+ total_display_records = modelCls.send(named_scope).count :conditions => conditions.join(" AND ")
122
+ else
123
+ total_records = modelCls.count :conditions => init_conditions.join(" AND ")
124
+ total_display_records = modelCls.count :conditions => conditions.join(" AND ")
125
+ end
126
+ sort_column = params[:iSortCol_0].to_i
127
+ sort_column = 1 if sort_column == 0
128
+ current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
129
+ if named_scope
130
+ objects = modelCls.send(named_scope).paginate(:page => current_page,
131
+ :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
132
+ :conditions => conditions.join(" AND "),
133
+ :per_page => params[:iDisplayLength])
134
+ else
135
+ objects = modelCls.paginate(:page => current_page,
136
+ :order => "#{columns[sort_column][:name]} #{params[:sSortDir_0]}",
137
+ :conditions => conditions.join(" AND "),
138
+ :per_page => params[:iDisplayLength])
139
+ end
140
+ #logger.info("------conditions is #{conditions}")
141
+ data = objects.collect do |instance|
142
+ columns.collect { |column| datatables_instance_get_value(instance, column) }
143
+ end
144
+ render :text => {:iTotalRecords => total_records,
145
+ :iTotalDisplayRecords => total_display_records,
146
+ :aaData => data,
147
+ :sEcho => params[:sEcho].to_i}.to_json
148
+ end
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ #
155
+ # Takes a list of columns from options and transforms them
156
+ #
157
+ def options_to_columns(options)
158
+ columns = []
159
+ options[:columns].each do |column|
160
+ if column.kind_of? Symbol # a column from the database, we don't need to do anything
161
+ columns << {:name => column, :attribute => column}
162
+ elsif column.kind_of? Hash
163
+ columns << {:name => column[:name], :special => column}
164
+ end
165
+ end
166
+ columns
167
+ end
168
+
169
+ def define_columns(cls, columns, action)
170
+ define_method "datatable_#{action}_columns".to_sym do
171
+ columnNames = {}
172
+ columns.each do |column|
173
+ columnName = ''
174
+ if column[:method] or column[:eval]
175
+ columnName << I18n.t(column[:name], :default => column[:name].to_s)
176
+ else
177
+ columnName << I18n.t(column[:name].to_sym, :default => column[:name].to_s)
178
+ end
179
+ columnName << ' *' unless column.has_key?(:attribute)
180
+ columnNames[columnName] = column.has_key?(:attribute) ? true : false
181
+ end
182
+
183
+ columnNames
184
+ end
185
+ end
186
+ end
187
+
188
+ # gets the value for a column and row
189
+ def datatables_instance_get_value(instance, column)
190
+ if column[:attribute]
191
+ val = instance.send(column[:attribute].to_sym)
192
+ return I18n.t(val.to_s.to_sym, :default => val.to_s) if not val.blank?
193
+ return ''
194
+ elsif column[:special]
195
+ special = column[:special]
196
+
197
+ if special[:method]
198
+ return method(special[:method].to_sym).call(instance)
199
+ elsif special[:eval]
200
+ proc = lambda { obj = instance; binding }
201
+ return Kernel.eval(special[:eval], proc.call)
202
+ end
203
+ end
204
+ return "value not found"
205
+ end
206
+
207
+ def datatable_source(name)
208
+ {:action => name, :attrs => method("datatable_#{name}_columns".to_sym).call}
209
+ end
210
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: data_tables
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Duane Compton
9
+ - Calvin Bascom
10
+ - Yi Su
11
+ - Chris Moos
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2012-10-10 00:00:00.000000000 Z
16
+ dependencies: []
17
+ description: Originally a plugin
18
+ email: Duane.Compton@gmail.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - lib/data_tables.rb
24
+ - lib/data_tables/data_tables_helper.rb
25
+ homepage: http://rubygems.org/gems/data_tables
26
+ licenses: []
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 1.8.24
46
+ signing_key:
47
+ specification_version: 3
48
+ summary: Rails friendly interface into DataTables
49
+ test_files: []