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.
- data/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/VERSION +1 -0
- data/lib/active-list.rb +37 -0
- data/lib/active-list/action_pack.rb +48 -0
- data/lib/active-list/columns/action_column.rb +70 -0
- data/lib/active-list/columns/data_column.rb +138 -0
- data/lib/active-list/columns/field_column.rb +29 -0
- data/lib/active-list/compass/stylesheets/_active-list.scss +7 -0
- data/lib/active-list/compass/stylesheets/active-list/_background.scss +37 -0
- data/lib/active-list/compass/stylesheets/active-list/_minimal.scss +89 -0
- data/lib/active-list/compass/stylesheets/active-list/_theme.scss +161 -0
- data/lib/active-list/definition.rb +103 -0
- data/lib/active-list/exporters.rb +71 -0
- data/lib/active-list/exporters/csv_exporter.rb +30 -0
- data/lib/active-list/exporters/excel_csv_exporter.rb +36 -0
- data/lib/active-list/exporters/open_document_spreadsheet_exporter.rb +81 -0
- data/lib/active-list/finder.rb +133 -0
- data/lib/active-list/generator.rb +88 -0
- data/lib/active-list/rails/engine.rb +11 -0
- data/lib/active-list/renderers.rb +28 -0
- data/lib/active-list/renderers/simple_renderer.rb +333 -0
- data/lib/assets/images/active-list.png +0 -0
- data/lib/assets/javascripts/active-list.jquery.js +128 -0
- data/lib/assets/stylesheets/active-list.css.scss +7 -0
- metadata +156 -0
@@ -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, ' ∅ '.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(/\'/,''')) + '</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(/\'/,''') + '</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(/\'/,''') + '</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(/\'/,'''), :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)
|