active-list 4.0.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,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)