active-list 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,133 @@
1
+ module ActiveList
2
+
3
+ # Manage data query
4
+ class Table
5
+
6
+ # Generate select code for the table taking all parameters in account
7
+ def select_data_code(options = {})
8
+ paginate = (options.has_key?(:paginate) ? options[:paginate] : self.paginate?)
9
+ # Check order
10
+ unless self.options.keys.include?(:order)
11
+ columns = self.table_columns
12
+ if columns.size > 0
13
+ self.options[:order] = columns[0].name.to_s # self.model.connection.quote_column_name(columns[0].name.to_s)
14
+ else
15
+ raise ArgumentError.new("Option :order is needed for the list :#{self.name}")
16
+ end
17
+ end
18
+
19
+ # Find data
20
+ query_code = "#{self.model.name}"
21
+ query_code << ".select(#{self.select_code})" if self.select_code
22
+ query_code << ".where(#{self.conditions_code})" unless self.options[:conditions].blank?
23
+ query_code << ".joins(#{self.options[:joins].inspect})" unless self.options[:joins].blank?
24
+ query_code << ".includes(#{self.includes_hash.inspect})" unless self.includes_hash.empty?
25
+
26
+ code = ""
27
+ code << "#{self.records_variable_name}_count = #{query_code}.count\n"
28
+ if paginate
29
+ code << "#{self.records_variable_name}_limit = (list_params[:per_page]||25).to_i\n"
30
+ code << "#{self.records_variable_name}_page = (list_params[:page]||1).to_i\n"
31
+ code << "#{self.records_variable_name}_page = 1 if #{self.records_variable_name}_page < 1\n"
32
+ code << "#{self.records_variable_name}_offset = (#{self.records_variable_name}_page-1)*#{self.records_variable_name}_limit\n"
33
+ code << "#{self.records_variable_name}_last = (#{self.records_variable_name}_count.to_f/#{self.records_variable_name}_limit).ceil.to_i\n"
34
+ code << "#{self.records_variable_name}_last = 1 if #{self.records_variable_name}_last < 1\n"
35
+ code << "return #{self.view_method_name}(options.merge(:page=>1)) if 1 > #{self.records_variable_name}_page\n"
36
+ code << "return #{self.view_method_name}(options.merge(:page=>#{self.records_variable_name}_last)) if #{self.records_variable_name}_page > #{self.records_variable_name}_last\n"
37
+ end
38
+ code << "#{self.records_variable_name} = #{query_code}"
39
+ if paginate
40
+ code << ".offset(#{self.records_variable_name}_offset)"
41
+ code << ".limit(#{self.records_variable_name}_limit)"
42
+ end
43
+ code << ".order(order)||{}\n"
44
+ return code
45
+ end
46
+
47
+ protected
48
+
49
+ # Compute includes Hash
50
+ def includes_hash
51
+ hash = {}
52
+ for column in self.columns
53
+ if through = column.options[:through]
54
+ through = [through] unless through.is_a? Array
55
+ h = hash
56
+ for x in through
57
+ h[x] = {} unless h[x].is_a? Hash
58
+ h = h[x]
59
+ end
60
+ end
61
+ end
62
+ return hash
63
+ end
64
+
65
+
66
+ # Generate the code from a conditions option
67
+ def conditions_code
68
+ conditions = self.options[:conditions]
69
+ code = ''
70
+ case conditions
71
+ when Array
72
+ case conditions[0]
73
+ when String # SQL
74
+ code += '["'+conditions[0].to_s+'"'
75
+ code += ', '+conditions[1..-1].collect{|p| sanitize_condition(p)}.join(', ') if conditions.size>1
76
+ code += ']'
77
+ when Symbol # Method
78
+ code += conditions[0].to_s+'('
79
+ code += conditions[1..-1].collect{|p| sanitize_condition(p)}.join(', ') if conditions.size>1
80
+ code += ')'
81
+ else
82
+ raise ArgumentError.new("First element of an Array can only be String or Symbol.")
83
+ end
84
+ when Hash # SQL
85
+ code += '{'+conditions.collect{|key, value| ':'+key.to_s+'=>'+sanitize_condition(value)}.join(',')+'}'
86
+ when Symbol # Method
87
+ code += conditions.to_s+"(options)"
88
+ when String
89
+ code += "("+conditions.gsub(/\s*\n\s*/,';')+")"
90
+ else
91
+ raise ArgumentError.new("Unsupported type for conditions: #{conditions.inspect}")
92
+ end
93
+ return code
94
+ end
95
+
96
+ def select_code
97
+ return nil unless self.options[:distinct] or self.options[:select]
98
+ code = ""
99
+ code << "DISTINCT " if self.options[:distinct]
100
+ code << "#{self.model.table_name}.*"
101
+ if self.options[:select]
102
+ code << self.options[:select].collect{|k, v| ", #{k[0].to_s+'.'+k[1].to_s} AS #{v}" }.join
103
+ end
104
+ return "'"+code+"'"
105
+ end
106
+
107
+
108
+ def sanitize_condition(value)
109
+ if value.is_a? Array
110
+ if value.size==1 and value[0].is_a? String
111
+ value[0].to_s
112
+ else
113
+ value.inspect
114
+ end
115
+ elsif value.is_a? String
116
+ '"'+value.gsub('"','\"')+'"'
117
+ elsif [Date, DateTime].include? value.class
118
+ '"'+value.to_formatted_s(:db)+'"'
119
+ elsif value.is_a? NilClass
120
+ 'nil'
121
+ else
122
+ value.to_s
123
+ end
124
+ end
125
+
126
+
127
+ end
128
+
129
+
130
+ end
131
+
132
+
133
+
@@ -0,0 +1,88 @@
1
+ # encoding: UTF-8
2
+ require "active-list/finder"
3
+ require "active-list/exporters"
4
+ require "active-list/renderers"
5
+
6
+ module ActiveList
7
+
8
+ class Table
9
+
10
+ def view_method_name
11
+ @options[:view_method_name]
12
+ end
13
+
14
+ def controller_method_name
15
+ @options[:controller_method_name]
16
+ end
17
+
18
+ def records_variable_name
19
+ @options[:records_variable_name]
20
+ end
21
+
22
+ def renderer
23
+ ActiveList.renderers[@options[:renderer]]
24
+ end
25
+
26
+
27
+ def generate_controller_method_code
28
+ code = "# encoding: utf-8\n"
29
+ code << "def #{self.controller_method_name}\n"
30
+ code << self.session_initialization_code.gsub(/^/, ' ')
31
+ code << " respond_to do |format|\n"
32
+ code << " format.html do\n"
33
+ code << " if request.xhr?\n"
34
+ code << self.renderer.remote_update_code(self).gsub(/^/, ' ')
35
+ code << " else\n"
36
+ code << " render(:inline=>'<%=#{self.view_method_name}-%>', :layout=>true)\n"
37
+ code << " end\n"
38
+ code << " end\n"
39
+ for format, exporter in ActiveList.exporters
40
+ code << " format.#{format} do\n"
41
+ code << exporter.send_data_code(self).gsub(/^/, ' ')
42
+ code << " end\n"
43
+ end
44
+ code << " end\n"
45
+ code << "end\n"
46
+ # code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
47
+ return code
48
+ end
49
+
50
+ def generate_view_method_code
51
+ code = "# encoding: utf-8\n"
52
+ code += "def #{self.view_method_name}(options={}, &block)\n"
53
+ code += self.session_initialization_code.gsub(/^/, ' ')
54
+ code += self.renderer.build_table_code(self).gsub(/^/, ' ')
55
+ code += "end\n"
56
+ # code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
57
+ return code
58
+ end
59
+
60
+
61
+ def session_initialization_code
62
+ code = "options = {} unless options.is_a? Hash\n"
63
+ code += "options = (params||{}).merge(options)\n"
64
+ # Session values
65
+ code += "session[:list] = {} unless session[:list].is_a? Hash\n"
66
+ code += "session[:list][:#{self.view_method_name}] = {} unless session[:list][:#{self.view_method_name}].is_a? Hash\n"
67
+ code += "list_params = session[:list][:#{self.view_method_name}]\n"
68
+ code += "list_params[:hidden_columns] = [] unless list_params[:hidden_columns].is_a? Array\n"
69
+ for parameter, convertor in @parameters.sort{|a,b| a[0].to_s <=> b[0].to_s}
70
+ expr = "options['#{self.name}_#{parameter}'] || options['#{parameter}'] || list_params[:#{parameter}]"
71
+ expr += " || #{@options[parameter]}" unless @options[parameter].blank?
72
+ code += "list_params[:#{parameter}] = (#{expr}).#{convertor}\n"
73
+ end
74
+ # Order
75
+ code += "order = #{self.options[:order] ? self.options[:order].inspect : 'nil'}\n"
76
+ code += "if (col = {"+self.sortable_columns.collect{|c| "'#{c.id}'=>'#{c.name}'"}.join(', ')+"}[list_params[:sort]])\n"
77
+ code += " list_params[:dir] ||= 'asc'\n"
78
+ code += " if list_params[:dir] == 'asc' or list_params[:dir] == 'desc'\n"
79
+ code += " order = #{@model.name}.connection.quote_column_name(col)+' '+list_params[:dir]\n"
80
+ code += " end\n"
81
+ code += "end\n"
82
+
83
+ return code
84
+ end
85
+
86
+
87
+ end
88
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveList
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ engine_name "active_list"
5
+ initializer "active_list.integrate_methods" do |app|
6
+ ::ActionController::Base.send(:include, ActiveList::ActionController)
7
+ ::ActionView::Base.send(:include, ActiveList::ViewsHelper)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+
3
+ module ActiveList
4
+
5
+ mattr_reader :renderers
6
+ @@renderers = {}
7
+
8
+ def self.register_renderer(name, renderer)
9
+ raise ArgumentError.new("A renderer must be ActiveList::Renderer") unless renderer.ancestors.include? ActiveList::Renderer
10
+ @@renderers[name] = renderer.new
11
+ end
12
+
13
+ class Renderer
14
+
15
+ def remote_update_code(table)
16
+ raise NotImplementedError.new("#{self.class.name}#remote_update_code is not implemented.")
17
+ end
18
+
19
+ def build_data_code(table)
20
+ raise NotImplementedError.new("#{self.class.name}#build_table_code is not implemented.")
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+
28
+ require "active-list/renderers/simple_renderer"
@@ -0,0 +1,333 @@
1
+ module ActiveList
2
+
3
+ class SimpleRenderer < ActiveList::Renderer
4
+
5
+ DATATYPE_ABBREVIATION = {
6
+ :binary => :bin,
7
+ :boolean => :bln,
8
+ :date => :dat,
9
+ :datetime => :dtt,
10
+ :decimal => :dec,
11
+ :float =>:flt,
12
+ :integer =>:int,
13
+ :string =>:str,
14
+ :text => :txt,
15
+ :time => :tim,
16
+ :timestamp => :dtt
17
+ }
18
+
19
+ def remote_update_code(table)
20
+ code = "if params[:column] and params[:visibility]\n"
21
+ code << " column = params[:column].to_s\n"
22
+ code << " list_params[:hidden_columns].delete(column) if params[:visibility] == 'shown'\n"
23
+ code << " list_params[:hidden_columns] << column if params[:visibility] == 'hidden'\n"
24
+ code << " head :ok\n"
25
+ code << "elsif params[:only]\n"
26
+ code << " render(:inline=>'<%=#{table.view_method_name}(:only => params[:only])-%>')\n"
27
+ code << "else\n"
28
+ code << " render(:inline=>'<%=#{table.view_method_name}-%>')\n"
29
+ code << "end\n"
30
+ return code
31
+ end
32
+
33
+ def build_table_code(table)
34
+ record = "r"
35
+ child = "c"
36
+
37
+ colgroup = columns_definition_code(table)
38
+ header = header_code(table)
39
+ extras = extras_code(table)
40
+ tbody = columns_to_cells(table, :body, :record=>record)
41
+
42
+ code = table.select_data_code
43
+ code << "tbody = '<tbody data-total=\"'+#{table.records_variable_name}_count.to_s+'\""
44
+ if table.paginate?
45
+ code << " data-per-page=\"'+#{table.records_variable_name}_limit.to_s+'\""
46
+ code << " data-pages-count=\"'+#{table.records_variable_name}_last.to_s+'\""
47
+ # code << " data-page-label=\"'+::I18n.translate('list.pagination.showing_x_to_y_of_total', :x => (#{table.records_variable_name}_offset + 1), :y => (#{table.records_variable_name}_offset+#{table.records_variable_name}_limit), :total => #{table.records_variable_name}_count)+'\""
48
+ end
49
+ code << ">'\n"
50
+ code << "if #{table.records_variable_name}_count > 0\n"
51
+ code << " reset_cycle('list')\n"
52
+ code << " for #{record} in #{table.records_variable_name}\n"
53
+ line_class = "cycle('odd', 'even', :name=>'list')"
54
+ line_class << "+' '+("+table.options[:line_class].to_s.gsub(/RECORD/, record)+').to_s' unless table.options[:line_class].nil?
55
+ code << " tbody << content_tag(:tr, (#{tbody}).html_safe, :class=>#{line_class})\n"
56
+ if table.options[:children].is_a? Symbol
57
+ children = table.options[:children].to_s
58
+ child_tbody = columns_to_cells(table, :children, :record=>child)
59
+ code << " for #{child} in #{record}.#{children}\n"
60
+ code << " tbody << content_tag(:tr, (#{child_tbody}).html_safe, {:class=>#{line_class}+' child'})\n"
61
+ code << " end\n"
62
+ end
63
+ code << " end\n"
64
+ code << "else\n"
65
+ code << " tbody << '<tr class=\"empty\"><td colspan=\"#{table.columns.size+1}\">' + ::I18n.translate('list.no_records') + '</td></tr>'\n"
66
+ code << "end\n"
67
+ code << "tbody << '</tbody>'\n"
68
+ code << "return tbody.html_safe if options[:only] == 'body' or options[:only] == 'tbody'\n"
69
+
70
+ code << "html = ''\n"
71
+ code << "html << '<div id=\"#{table.name}\" data-list-source=\"'+h(url_for({:action => '#{table.controller_method_name}'}))+'\" class=\"active-list\""
72
+ code << "data-list-current-page=\"' + #{table.records_variable_name}_page.to_s + '\" data-list-page-size=\"' + #{table.records_variable_name}_limit.to_s + '\""
73
+ code << "data-list-sort-by=\"' + list_params[:sort].to_s + '\" data-list-sort-dir=\"' + list_params[:dir].to_s + '\""
74
+ code << ">'\n"
75
+ code << "html << '<table class=\"list\">'\n"
76
+ code << "html << (#{header})\n"
77
+ code << "if block_given?\n"
78
+ code << " html << '<tfoot>'+capture("+table.columns.collect{|c| {:name=>c.name, :id=>c.id}}.inspect+", &block)+'</tfoot>'\n"
79
+ code << "end\n"
80
+ code << "html << tbody\n"
81
+ code << "html << '</table>'\n"
82
+ code << "html << #{extras}\n" if extras
83
+ code << "html << '</div>'\n"
84
+ code << "return html.html_safe\n"
85
+ return code
86
+ end
87
+
88
+
89
+
90
+ def columns_to_cells(table, nature, options={})
91
+ columns = table.columns
92
+ code = ''
93
+ record = options[:record]||'RECORD'
94
+ for column in columns
95
+ if nature==:header
96
+ raise Exception.new("Ohohoh")
97
+ else
98
+ case column.class.name
99
+ when DataColumn.name
100
+ style = column.options[:style]||''
101
+ style = style.gsub(/RECORD/, record)+"+" if style.match(/RECORD/)
102
+ style << "'"
103
+ if nature!=:children or (not column.options[:children].is_a? FalseClass and nature==:children)
104
+ datum = column.datum_code(record, nature==:children)
105
+ if column.datatype == :boolean
106
+ datum = "content_tag(:div, '', :class=>'checkbox-'+("+datum.to_s+" ? 'true' : 'false'))"
107
+ end
108
+ if [:date, :datetime, :timestamp].include? column.datatype
109
+ datum = "(#{datum}.nil? ? '' : ::I18n.localize(#{datum}))"
110
+ end
111
+ if !column.options[:currency].is_a?(FalseClass) and (currency = column.options[:currency]) # column.datatype == :decimal and
112
+ currency = currency[nature] if currency.is_a?(Hash)
113
+ currency = :currency if currency.is_a?(TrueClass)
114
+ currency = "RECORD.#{currency}" if currency.is_a?(Symbol)
115
+ raise Exception.new("Option :currency is not valid. Hash, Symbol or true/false") unless currency.is_a?(String)
116
+ currency.gsub!(/RECORD/, record)
117
+ datum = "(#{datum}.nil? ? '' : ::I18n.localize(#{datum}, :currency => #{currency}))"
118
+ elsif column.datatype == :decimal
119
+ datum = "(#{datum}.nil? ? '' : ::I18n.localize(#{datum}))"
120
+ end
121
+ if column.options[:url].is_a?(TrueClass) and nature==:body
122
+ datum = "(#{datum}.blank? ? '' : link_to(#{datum}, {:controller=>:#{column.class_name.underscore.pluralize}, :action=>:show, :id=>#{column.record_expr(record)+'.id'}}))"
123
+ elsif column.options[:url].is_a?(Hash) and nature==:body
124
+ column.options[:url][:id] ||= column.record_expr(record)+'.id'
125
+ column.options[:url][:action] ||= :show
126
+ column.options[:url][:controller] ||= column.class_name.underscore.pluralize.to_sym
127
+ url = column.options[:url].collect{|k, v| ":#{k}=>"+(v.is_a?(String) ? v.gsub(/RECORD/, record) : v.inspect)}.join(", ")
128
+ datum = "(#{datum}.blank? ? '' : link_to(#{datum}, url_for(#{url})))"
129
+ elsif column.options[:mode] == :download# and !datum.nil?
130
+ datum = "(#{datum}.blank? ? '' : link_to(tg('download'), url_for_file_column("+record+",'#{column.name}')))"
131
+ elsif column.options[:mode]||column.name == :email
132
+ # datum = 'link_to('+datum+', "mailto:#{'+datum+'}")'
133
+ datum = "(#{datum}.blank? ? '' : mail_to(#{datum}))"
134
+ elsif column.options[:mode]||column.name == :website
135
+ datum = "(#{datum}.blank? ? '' : link_to("+datum+", "+datum+"))"
136
+ elsif column.name==:color
137
+ style << "background: #'+"+column.datum_code(record)+"+';"
138
+ elsif column.name.to_s.match(/(^|\_)currency$/) and column.datatype == :string and column.limit == 3
139
+ datum = "(#{datum}.blank? ? '' : ::I18n.currency_label(#{datum}))"
140
+ elsif column.name==:language and column.datatype == :string and column.limit <= 8
141
+ datum = "(#{datum}.blank? ? '' : ::I18n.translate('languages.'+#{datum}))"
142
+ elsif column.name==:country and column.datatype == :string and column.limit <= 8
143
+ datum = "(#{datum}.blank? ? '' : (image_tag('countries/'+#{datum}.to_s+'.png')+' '+::I18n.translate('countries.'+#{datum})).html_safe)"
144
+ elsif column.datatype == :string
145
+ datum = "h("+datum+")"
146
+ end
147
+ else
148
+ datum = 'nil'
149
+ end
150
+ code << "content_tag(:td, #{datum}, :class=>\"#{column_classes(column)}\""
151
+ code << ", :style=>"+style+"'" unless style[1..-1].blank?
152
+ code << ")"
153
+ when CheckBoxColumn.name
154
+ code << "content_tag(:td,"
155
+ if nature==:body
156
+ code << "hidden_field_tag('#{table.name}['+#{record}.id.to_s+'][#{column.name}]', 0, :id=>nil)+"
157
+ code << "check_box_tag('#{table.name}['+#{record}.id.to_s+'][#{column.name}]', 1, #{column.options[:value] ? column.options[:value].to_s.gsub(/RECORD/, record) : record+'.'+column.name.to_s}, :id=>'#{table.name}_'+#{record}.id.to_s+'_#{column.name}')"
158
+ else
159
+ code << "''"
160
+ end
161
+ code << ", :class=>\"#{column_classes(column)}\")"
162
+ when TextFieldColumn.name
163
+ code << "content_tag(:td,"
164
+ if nature==:body
165
+ code << "text_field_tag('#{table.name}['+#{record}.id.to_s+'][#{column.name}]', #{column.options[:value] ? column.options[:value].to_s.gsub(/RECORD/, record) : record+'.'+column.name.to_s}, :id=>'#{table.name}_'+#{record}.id.to_s+'_#{column.name}'#{column.options[:size] ? ', :size=>'+column.options[:size].to_s : ''})"
166
+ else
167
+ code << "''"
168
+ end
169
+ code << ", :class=>\"#{column_classes(column)}\")"
170
+ when ActionColumn.name
171
+ code << "content_tag(:td, "+(nature==:body ? column.operation(record) : "''")+", :class=>\"#{column_classes(column)}\")"
172
+ else
173
+ code << "content_tag(:td, '&#160;&#8709;&#160;'.html_safe)"
174
+ end
175
+ code << "+\n " # unless code.blank?
176
+ end
177
+ end
178
+ if nature==:header
179
+ code << "'<th class=\"spe\">#{menu_code(table)}</th>'"
180
+ else
181
+ code << "content_tag(:td)"
182
+ end
183
+
184
+ return code
185
+ end
186
+
187
+
188
+ # Produces main menu code
189
+ def menu_code(table)
190
+ menu = "<div class=\"list-menu\">"
191
+ menu << "<a class=\"list-menu-start\"><span class=\"icon\"></span><span class=\"text\">' + h(::I18n.translate('list.menu').gsub(/\'/,'&#39;')) + '</span></a>"
192
+ menu << "<ul>"
193
+ if table.paginate?
194
+ # Per page
195
+ list = [5, 10, 20, 50, 100, 200]
196
+ list << table.options[:per_page].to_i if table.options[:per_page].to_i > 0
197
+ list = list.uniq.sort
198
+ menu << "<li class=\"parent\">"
199
+ menu << "<a class=\"pages\"><span class=\"icon\"></span><span class=\"text\">' + ::I18n.translate('list.items_per_page').gsub(/\'/,'&#39;') + '</span></a><ul>"
200
+ for n in list
201
+ menu << "<li data-list-change-page-size=\"#{n}\" '+(list_params[:per_page] == #{n} ? ' class=\"check\"' : '')+'><span class=\"icon\"></span><span class=\"text\">'+h(::I18n.translate('list.x_per_page', :count=>#{n}))+'</span></li>"
202
+ end
203
+ menu << "</ul></li>"
204
+ end
205
+
206
+ # Column selector
207
+ menu << "<li class=\"parent\">"
208
+ menu << "<a class=\"columns\"><span class=\"icon\"></span><span class=\"text\">' + ::I18n.translate('list.columns').gsub(/\'/,'&#39;') + '</span></a><ul>"
209
+ for column in table.data_columns
210
+ menu << "<li data-list-toggle-column=\"#{column.id}\" class=\"'+(list_params[:hidden_columns].include?('#{column.id}') ? 'unchecked' : 'checked')+'\"><span class=\"icon\"></span><span class=\"text\">'+h(#{column.header_code})+'</span></li>"
211
+ end
212
+ menu << "</ul></li>"
213
+
214
+ # Separator
215
+ menu << "<li class=\"separator\"></li>"
216
+ # Exports
217
+ for format, exporter in ActiveList.exporters
218
+ menu << "<li class=\"export #{exporter.name}\">' + link_to(params.merge(:action=>:#{table.controller_method_name}, :sort=>list_params[:sort], :dir=>list_params[:dir], :format=>'#{format}'), :class=>\"export\") { '<span class=\"icon\"></span>'.html_safe + content_tag('span', ::I18n.translate('list.export_as', :exported=>::I18n.translate('list.export.formats.#{format}')).gsub(/\'/,'&#39;'), :class=>'text')} + '</li>"
219
+ end
220
+ menu << "</ul></div>"
221
+ return menu
222
+ end
223
+
224
+ # Produces the code to create the header line using top-end menu for columns
225
+ # and pagination management
226
+ def header_code(table)
227
+ code = "'<thead><tr>"
228
+ for column in table.columns
229
+ code << "<th data-list-column=\"#{column.id}\""
230
+ code << " data-list-column-cells=\"#{column.simple_id}\""
231
+ code << " data-list-column-sort=\"'+(list_params[:sort]!='#{column.id}' ? 'asc' : list_params[:dir] == 'asc' ? 'desc' : 'asc')+'\"" if column.sortable?
232
+ code << " class=\"#{column_classes(column, true, true)}\""
233
+ code << ">"
234
+ code << "<span class=\"text\">'+h(#{column.header_code})+'</span>"
235
+ code << "<span class=\"icon\"></span>"
236
+ code << "</th>"
237
+ end
238
+ code << "<th class=\"spe\">#{menu_code(table)}</th>"
239
+ code << "</tr></thead>'"
240
+ return code
241
+ end
242
+
243
+ # Produces the code to create bottom menu and pagination
244
+ def extras_code(table)
245
+ code, pagination = nil, ''
246
+
247
+ if table.paginate?
248
+ current_page = "#{table.records_variable_name}_page"
249
+ last_page = "#{table.records_variable_name}_last"
250
+
251
+ pagination << "<div class=\"pagination\">"
252
+ pagination << "<a href=\"#\" data-list-move-to-page=\"1\" class=\"first-page\"' + (#{current_page} != 1 ? '' : ' disabled=\"true\"') + '>' + ::I18n.translate('list.pagination.first') + '</a>"
253
+ pagination << "<a href=\"#\" data-list-move-to-page=\"' + (#{current_page} - 1).to_s + '\" class=\"previous-page\"' + (#{current_page} != 1 ? '' : ' disabled=\"true\"') + '>' + ::I18n.translate('list.pagination.previous') + '</a>"
254
+
255
+ x = '@@PAGE-NUMBER@@'
256
+ y = '@@PAGE-COUNT@@'
257
+ pagination << "<span class=\"paginator\">'+::I18n.translate('list.page_x_on_y', :default=>'%{x} / %{y}', :x => '#{x}', :y =>'#{y}').html_safe.gsub('#{x}', ('<input type=\"number\" size=\"4\" data-list-move-to-page=\"value\" value=\"'+#{table.records_variable_name}_page.to_s+'\">').html_safe).gsub('#{y}', #{table.records_variable_name}_last.to_s) + '</span>"
258
+
259
+ pagination << "<a href=\"#\" data-list-move-to-page=\"' + (#{current_page} + 1).to_s + '\" class=\"next-page\"' + (#{current_page} != #{last_page} ? '' : ' disabled=\"true\"') + '>' + ::I18n.translate('list.pagination.next')+'</a>"
260
+ pagination << "<a href=\"#\" data-list-move-to-page=\"' + (#{last_page}).to_s + '\" class=\"last-page\"' + (#{current_page} != #{last_page} ? '' : ' disabled=\"true\"') + '>' + ::I18n.translate('list.pagination.last')+'</a>"
261
+
262
+ pagination << "<span class=\"separator\"></span>"
263
+
264
+ pagination << "<span class=\"status\">'+::I18n.translate('list.pagination.showing_x_to_y_of_total', :x => (#{table.records_variable_name}_offset + 1), :y => (#{table.records_variable_name}_offset+#{table.records_variable_name}_limit), :total => #{table.records_variable_name}_count)+'</span>"
265
+ pagination << "</div>"
266
+
267
+ code = "(#{table.records_variable_name}_last > 1 ? '<div class=\"extras\">#{pagination}</div>' : '').html_safe"
268
+ end
269
+
270
+ return code
271
+ end
272
+
273
+ # Not used
274
+ def columns_definition_code(table)
275
+ code = table.columns.collect do |column|
276
+ "<col id=\\\"#{column.unique_id}\\\" class=\\\"#{column_classes(column, true)}\\\" data-cells-class=\\\"#{column.simple_id}\\\" href=\\\"\#\{url_for(:action=>:#{table.controller_method_name}, :column=>#{column.id.to_s.inspect})\}\\\" />"
277
+ end.join
278
+ return "\"#{code}\""
279
+ end
280
+
281
+ # Finds all default styles for column
282
+ def column_classes(column, without_id=false, without_interpolation=false)
283
+ classes, conds = [], []
284
+ conds << [:sor, "list_params[:sort]=='#{column.id}'"] if column.sortable?
285
+ conds << [:hidden, "list_params[:hidden_columns].include?('#{column.id}')"] if column.is_a? DataColumn
286
+ classes << column.options[:class].to_s.strip unless column.options[:class].blank?
287
+ classes << column.simple_id unless without_id
288
+ if column.is_a? ActionColumn
289
+ classes << :act
290
+ elsif column.is_a? DataColumn
291
+ classes << :col
292
+ classes << DATATYPE_ABBREVIATION[column.datatype]
293
+ classes << :url if column.options[:url].is_a?(Hash)
294
+ classes << column.name if [:code, :color, :country].include? column.name.to_sym
295
+ if column.options[:mode] == :download
296
+ classes << :dld
297
+ elsif column.options[:mode]||column.name == :email
298
+ classes << :eml
299
+ elsif column.options[:mode]||column.name == :website
300
+ classes << :web
301
+ end
302
+ elsif column.is_a? TextFieldColumn
303
+ classes << :tfd
304
+ elsif column.is_a? CheckBoxColumn
305
+ classes << :chk
306
+ else
307
+ classes << :unk
308
+ end
309
+ html = classes.join(' ').strip
310
+ if conds.size > 0
311
+ if without_interpolation
312
+ html << "' + "
313
+ html << conds.collect do |c|
314
+ "(#{c[1]} ? ' #{c[0]}' : '')"
315
+ end.join(' + ')
316
+ html << " + '"
317
+ else
318
+ html << conds.collect do |c|
319
+ "\#\{' #{c[0]}' if #{c[1]}\}"
320
+ end.join
321
+ end
322
+ end
323
+ return html
324
+ end
325
+
326
+
327
+ end
328
+
329
+
330
+ end
331
+
332
+
333
+ ActiveList.register_renderer(:simple_renderer, ActiveList::SimpleRenderer)