data_tables 0.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.
@@ -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: []