active-list 4.2.4 → 5.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.
- checksums.yaml +7 -0
- data/VERSION +1 -1
- data/{lib → app}/assets/images/active-list.png +0 -0
- data/app/assets/images/active-list.svg +415 -0
- data/{lib/assets/javascripts/active-list.jquery.js → app/assets/javascripts/active_list.jquery.js} +2 -2
- data/app/assets/stylesheets/active_list.css.scss +7 -0
- data/{lib/active-list/compass/stylesheets/active-list/_background.scss → app/assets/stylesheets/active_list/background.scss} +10 -8
- data/{lib/active-list/compass/stylesheets/active-list/_minimal.scss → app/assets/stylesheets/active_list/minimal.scss} +16 -16
- data/{lib/active-list/compass/stylesheets/active-list/_theme.scss → app/assets/stylesheets/active_list/theme.scss} +37 -37
- data/lib/active-list.rb +1 -37
- data/lib/active_list.rb +43 -0
- data/lib/active_list/action_pack.rb +46 -0
- data/lib/active_list/definition.rb +17 -0
- data/lib/active_list/definition/abstract_column.rb +54 -0
- data/lib/active_list/definition/action_column.rb +76 -0
- data/lib/active_list/definition/association_column.rb +80 -0
- data/lib/active_list/definition/attribute_column.rb +58 -0
- data/lib/active_list/definition/check_box_column.rb +17 -0
- data/lib/active_list/definition/data_column.rb +88 -0
- data/lib/active_list/definition/empty_column.rb +10 -0
- data/lib/active_list/definition/field_column.rb +20 -0
- data/lib/active_list/definition/status_column.rb +10 -0
- data/lib/active_list/definition/table.rb +159 -0
- data/lib/active_list/definition/text_field_column.rb +10 -0
- data/lib/active_list/exporters.rb +28 -0
- data/lib/active_list/exporters/abstract_exporter.rb +55 -0
- data/lib/active_list/exporters/csv_exporter.rb +32 -0
- data/lib/active_list/exporters/excel_csv_exporter.rb +38 -0
- data/lib/active_list/exporters/open_document_spreadsheet_exporter.rb +82 -0
- data/lib/active_list/generator.rb +122 -0
- data/lib/active_list/generator/finder.rb +150 -0
- data/lib/active_list/helpers.rb +33 -0
- data/lib/{active-list → active_list}/rails/engine.rb +3 -2
- data/lib/active_list/renderers.rb +25 -0
- data/lib/active_list/renderers/abstract_renderer.rb +29 -0
- data/lib/active_list/renderers/simple_renderer.rb +356 -0
- metadata +74 -55
- data/lib/active-list/action_pack.rb +0 -48
- data/lib/active-list/columns/action_column.rb +0 -83
- data/lib/active-list/columns/data_column.rb +0 -151
- data/lib/active-list/columns/field_column.rb +0 -29
- data/lib/active-list/compass/stylesheets/_active-list.scss +0 -7
- data/lib/active-list/definition.rb +0 -103
- data/lib/active-list/exporters.rb +0 -71
- data/lib/active-list/exporters/csv_exporter.rb +0 -30
- data/lib/active-list/exporters/excel_csv_exporter.rb +0 -36
- data/lib/active-list/exporters/open_document_spreadsheet_exporter.rb +0 -81
- data/lib/active-list/finder.rb +0 -134
- data/lib/active-list/generator.rb +0 -88
- data/lib/active-list/renderers.rb +0 -28
- data/lib/active-list/renderers/simple_renderer.rb +0 -335
- data/lib/assets/stylesheets/active-list.css.scss +0 -7
@@ -0,0 +1,28 @@
|
|
1
|
+
# require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
module ActiveList
|
3
|
+
|
4
|
+
module Exporters
|
5
|
+
|
6
|
+
def self.hash
|
7
|
+
ActiveList.exporters
|
8
|
+
end
|
9
|
+
|
10
|
+
autoload :AbstractExporter, 'active_list/exporters/abstract_exporter'
|
11
|
+
autoload :OpenDocumentSpreadsheetExporter, 'active_list/exporters/open_document_spreadsheet_exporter'
|
12
|
+
autoload :CsvExporter, 'active_list/exporters/csv_exporter'
|
13
|
+
autoload :ExcelCsvExporter, 'active_list/exporters/excel_csv_exporter'
|
14
|
+
end
|
15
|
+
|
16
|
+
mattr_reader :exporters
|
17
|
+
@@exporters = {}
|
18
|
+
|
19
|
+
def self.register_exporter(name, exporter)
|
20
|
+
raise ArgumentError.new("ActiveList::Exporters::AbstractExporter expected (got #{exporter.name}/#{exporter.ancestors.inspect})") unless exporter < ActiveList::Exporters::AbstractExporter
|
21
|
+
@@exporters[name] = exporter
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
ActiveList.register_exporter(:ods, ActiveList::Exporters::OpenDocumentSpreadsheetExporter)
|
27
|
+
ActiveList.register_exporter(:csv, ActiveList::Exporters::CsvExporter)
|
28
|
+
ActiveList.register_exporter(:xcsv, ActiveList::Exporters::ExcelCsvExporter)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
module Exporters
|
4
|
+
|
5
|
+
class AbstractExporter
|
6
|
+
|
7
|
+
attr_reader :table, :generator
|
8
|
+
|
9
|
+
def initialize(generator)
|
10
|
+
@generator = generator
|
11
|
+
@table = generator.table
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_extension
|
15
|
+
"txt"
|
16
|
+
end
|
17
|
+
|
18
|
+
def mime_type
|
19
|
+
Mime::TEXT
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_data_code
|
23
|
+
raise NotImplementedError, "#{self.class.name}#format_data_code is not implemented."
|
24
|
+
end
|
25
|
+
|
26
|
+
def columns_headers(options={})
|
27
|
+
headers, columns = [], table.exportable_columns
|
28
|
+
for column in columns
|
29
|
+
datum = column.header_code
|
30
|
+
headers << (options[:encoding] ? datum+".to_s.encode('#{options[:encoding]}')" : datum)
|
31
|
+
end
|
32
|
+
return headers
|
33
|
+
end
|
34
|
+
|
35
|
+
def columns_to_array(nature, options={})
|
36
|
+
columns = table.exportable_columns
|
37
|
+
|
38
|
+
array = []
|
39
|
+
record = options[:record] || 'record_of_the_death'
|
40
|
+
for column in columns
|
41
|
+
if column.is_a?(ActiveList::Definition::AbstractColumn)
|
42
|
+
if nature == :header
|
43
|
+
datum = column.header_code
|
44
|
+
else
|
45
|
+
datum = column.exporting_datum_code(record)
|
46
|
+
end
|
47
|
+
array << (options[:encoding] ? datum+".to_s.encode('#{options[:encoding]}')" : datum)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return array
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
module Exporters
|
4
|
+
|
5
|
+
class CsvExporter < AbstractExporter
|
6
|
+
|
7
|
+
def file_extension
|
8
|
+
"csv"
|
9
|
+
end
|
10
|
+
|
11
|
+
def mime_type
|
12
|
+
Mime::CSV
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_data_code
|
16
|
+
record = "r"
|
17
|
+
code = generator.select_data_code(paginate: false)
|
18
|
+
code << "data = ActiveList::CSV.generate do |csv|\n"
|
19
|
+
code << " csv << [#{columns_to_array(:header).join(', ')}]\n"
|
20
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
21
|
+
code << " csv << [#{columns_to_array(:body, record: record).join(', ')}]\n"
|
22
|
+
code << " end\n"
|
23
|
+
code << "end\n"
|
24
|
+
code << "send_data(data, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_') + '.#{self.file_extension}')\n"
|
25
|
+
return code.c
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Register XCSV format unless is already set
|
4
|
+
Mime::Type.register("text/csv", :xcsv) unless defined? Mime::XCSV
|
5
|
+
|
6
|
+
module ActiveList
|
7
|
+
|
8
|
+
module Exporters
|
9
|
+
|
10
|
+
class ExcelCsvExporter < CsvExporter
|
11
|
+
|
12
|
+
def file_extension
|
13
|
+
"csv"
|
14
|
+
end
|
15
|
+
|
16
|
+
def mime_type
|
17
|
+
Mime::XCSV
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_data_code
|
21
|
+
record = "r"
|
22
|
+
code = generator.select_data_code(paginate: false)
|
23
|
+
encoding = "CP1252"
|
24
|
+
code << "data = ActiveList::CSV.generate(:col_sep => ';') do |csv|\n"
|
25
|
+
code << " csv << [#{columns_to_array(:header, encoding: encoding).join(', ')}]\n"
|
26
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
27
|
+
code << " csv << [#{columns_to_array(:body, record: record, encoding: encoding).join(', ')}]\n"
|
28
|
+
code << " end\n"
|
29
|
+
code << "end\n"
|
30
|
+
code << "send_data(data, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')+'.#{self.file_extension}')\n"
|
31
|
+
return code.c
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'zip'
|
3
|
+
|
4
|
+
# Register ODS format unless is already set
|
5
|
+
Mime::Type.register("application/vnd.oasis.opendocument.spreadsheet", :ods) unless defined? Mime::ODS
|
6
|
+
|
7
|
+
module ActiveList
|
8
|
+
|
9
|
+
module Exporters
|
10
|
+
|
11
|
+
class OpenDocumentSpreadsheetExporter < AbstractExporter
|
12
|
+
|
13
|
+
DATE_ELEMENTS = {
|
14
|
+
"m" => "<number:month number:style=\"long\"/>",
|
15
|
+
"d" => "<number:day number:style=\"long\"/>",
|
16
|
+
"Y" => "<number:year/>"
|
17
|
+
}
|
18
|
+
|
19
|
+
def file_extension
|
20
|
+
"ods"
|
21
|
+
end
|
22
|
+
|
23
|
+
def mime_type
|
24
|
+
Mime::ODS
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_data_code
|
28
|
+
xml_escape = "to_s.gsub('&', '&').gsub('\\'', ''').gsub('<', '<').gsub('>', '>')"
|
29
|
+
xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
|
30
|
+
record = "r"
|
31
|
+
code = generator.select_data_code(paginate: false)
|
32
|
+
code << "name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_')\n"
|
33
|
+
code << "file = ::Rails.root.join('tmp', 'export', 'active_list', name + rand.to_s+'.#{self.file_extension}')\n"
|
34
|
+
code << "FileUtils.mkdir_p(file.dirname)\n"
|
35
|
+
code << "Zip::OutputStream.open(file) do |zile|\n"
|
36
|
+
# MimeType in first place
|
37
|
+
code << " zile.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)\n"
|
38
|
+
code << " zile << '#{self.mime_type}'\n"
|
39
|
+
|
40
|
+
# Manifest
|
41
|
+
code << " zile.put_next_entry('META-INF/manifest.xml')\n"
|
42
|
+
code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:media-type=\"#{self.mime_type}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>')\n"
|
43
|
+
code << " zile.put_next_entry('content.xml')\n"
|
44
|
+
|
45
|
+
code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>')\n"
|
46
|
+
# Styles
|
47
|
+
code << " zile << ('<office:automatic-styles>"+
|
48
|
+
"<style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:use-optimal-column-width=\"true\"/></style:style>"+
|
49
|
+
"<style:style style:name=\"header\" style:family=\"table-cell\"><style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"/></style:style>"+
|
50
|
+
"<number:date-style style:name=\"K4D\" number:automatic-order=\"true\"><number:text>"+::I18n.translate("date.formats.default").gsub(/\%./){|x| "</number:text>"+DATE_ELEMENTS[x[1..1]]+"<number:text>"} +"</number:text></number:date-style><style:style style:name=\"ce1\" style:family=\"table-cell\" style:data-style-name=\"K4D\"/>"+
|
51
|
+
"</office:automatic-styles>')\n"
|
52
|
+
|
53
|
+
# Tables
|
54
|
+
code << " zile << ('<office:body><office:spreadsheet><table:table table:name=\"'+#{table.model.name}.model_name.human.#{xml_escape}+'\">')\n"
|
55
|
+
code << " zile << ('<table:table-column table:number-columns-repeated=\"#{table.exportable_columns.size}\"/>')\n"
|
56
|
+
code << " zile << ('<table:table-header-rows><table:table-row>"+columns_headers.collect{|h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>"}.join+"</table:table-row></table:table-header-rows>')\n"
|
57
|
+
code << " for #{record} in #{generator.records_variable_name}\n"
|
58
|
+
code << " zile << ('<table:table-row>"+table.exportable_columns.collect do |column|
|
59
|
+
"<table:table-cell"+(if column.numeric? or column.datatype==:decimal
|
60
|
+
" office:value-type=\"float\" office:value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
61
|
+
elsif column.datatype==:boolean
|
62
|
+
" office:value-type=\"boolean\" office:boolean-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
63
|
+
elsif column.datatype==:date
|
64
|
+
" office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
|
65
|
+
else
|
66
|
+
" office:value-type=\"string\""
|
67
|
+
end)+"><text:p>'+("+column.exporting_datum_code(record, true)+").#{xml_escape}+'</text:p></table:table-cell>"
|
68
|
+
end.join+"</table:table-row>')\n"
|
69
|
+
code << " end\n"
|
70
|
+
code << " zile << ('</table:table></office:spreadsheet></office:body></office:document-content>')\n"
|
71
|
+
code << "end\n"
|
72
|
+
code << "send_file(file, stream: false, type: #{self.mime_type.to_s.inspect}, disposition: 'inline', filename: name+'.#{self.file_extension}')\n"
|
73
|
+
code << "File.delete(file)\n" # Removes tmp files before they explode the disk
|
74
|
+
# raise code
|
75
|
+
return code
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActiveList
|
3
|
+
|
4
|
+
class Generator
|
5
|
+
|
6
|
+
attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name
|
7
|
+
|
8
|
+
def initialize(*args, &block)
|
9
|
+
options = args.extract_options!
|
10
|
+
@controller = options[:controller]
|
11
|
+
name = args.shift || @controller.controller_name.to_sym
|
12
|
+
model = (options[:model]||name).to_s.classify.constantize
|
13
|
+
@collection = !!(model.name == @controller.controller_name.to_s.classify)
|
14
|
+
@controller_method_name = "list#{'_'+name.to_s if name != @controller.controller_name.to_sym}"
|
15
|
+
@view_method_name = "_#{@controller.controller_name}_list_#{name}_tag"
|
16
|
+
@records_variable_name = "@#{name}"
|
17
|
+
@table = ActiveList::Definition::Table.new(name, model, options)
|
18
|
+
if block_given?
|
19
|
+
yield @table
|
20
|
+
else
|
21
|
+
@table.load_default_columns
|
22
|
+
end
|
23
|
+
@parameters = {:sort => :to_s, :dir => :to_s}
|
24
|
+
@parameters.merge!(:page => :to_i, :per_page => :to_i) if @table.paginate?
|
25
|
+
end
|
26
|
+
|
27
|
+
def collection?
|
28
|
+
@collection
|
29
|
+
end
|
30
|
+
|
31
|
+
def var_name(name)
|
32
|
+
"_#{name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def renderer
|
36
|
+
ActiveList::Renderers[@table.options[:renderer]].new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def controller_method_code
|
40
|
+
code = "# encoding: utf-8\n"
|
41
|
+
code << "def #{self.controller_method_name}\n"
|
42
|
+
code << self.session_initialization_code.dig
|
43
|
+
code << " respond_to do |format|\n"
|
44
|
+
code << " format.html do\n"
|
45
|
+
code << " if request.xhr?\n"
|
46
|
+
code << self.renderer.remote_update_code.dig(4)
|
47
|
+
code << " else\n"
|
48
|
+
code << " render(inline: '<%=#{self.view_method_name}-%>')\n" # , layout: action_has_layout?
|
49
|
+
code << " end\n"
|
50
|
+
code << " end\n"
|
51
|
+
for format, exporter in ActiveList::Exporters.hash
|
52
|
+
code << " format.#{format} do\n"
|
53
|
+
code << exporter.new(self).send_data_code.dig(3)
|
54
|
+
code << " end\n"
|
55
|
+
end
|
56
|
+
code << " end\n"
|
57
|
+
# Save preferences of user
|
58
|
+
if defined? User and User.instance_methods.include? :pref
|
59
|
+
code << " p = current_user.pref('list.#{self.view_method_name}', YAML::dump({}))\n"
|
60
|
+
code << " p.set! YAML::dump(#{var_name(:params)}.stringify_keys)\n"
|
61
|
+
end
|
62
|
+
code << "end\n"
|
63
|
+
# code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
|
64
|
+
unless ::Rails.env.production?
|
65
|
+
file = ::Rails.root.join("tmp", "code", "active_list", "controllers", self.controller.controller_path, self.controller_method_name + ".rb")
|
66
|
+
FileUtils.mkdir_p(file.dirname)
|
67
|
+
File.write(file, code)
|
68
|
+
end
|
69
|
+
return code
|
70
|
+
end
|
71
|
+
|
72
|
+
def view_method_code
|
73
|
+
code = "# encoding: utf-8\n"
|
74
|
+
code << "def #{self.view_method_name}(options={}, &block)\n"
|
75
|
+
code << self.session_initialization_code.dig
|
76
|
+
code << self.renderer.build_table_code.dig
|
77
|
+
code << "end\n"
|
78
|
+
# code.split("\n").each_with_index{|l, x| puts((x+1).to_s.rjust(4)+": "+l)}
|
79
|
+
unless ::Rails.env.production?
|
80
|
+
file = ::Rails.root.join("tmp", "code", "active_list", "views", self.controller.controller_path, self.view_method_name + ".rb")
|
81
|
+
FileUtils.mkdir_p(file.dirname)
|
82
|
+
File.write(file, code)
|
83
|
+
end
|
84
|
+
return code
|
85
|
+
end
|
86
|
+
|
87
|
+
def session_initialization_code
|
88
|
+
code = "options = {} unless options.is_a? Hash\n"
|
89
|
+
code << "options.update(params)\n"
|
90
|
+
if defined? User and User.instance_methods.include? :pref
|
91
|
+
code << "#{var_name(:params)} = YAML::load(current_user.pref('list.#{self.view_method_name}', YAML::dump({})).value).symbolize_keys\n"
|
92
|
+
code << "#{var_name(:params)} = {} unless #{var_name(:params)}.is_a?(Hash)\n"
|
93
|
+
else
|
94
|
+
code << "#{var_name(:params)} = {}\n"
|
95
|
+
end
|
96
|
+
code << "#{var_name(:params)}.update(options.symbolize_keys)\n"
|
97
|
+
code << "unless #{var_name(:params)}[:hidden_columns].is_a? Array\n"
|
98
|
+
code << " #{var_name(:params)}[:hidden_columns] = #{@table.hidden_columns.map(&:name).map(&:to_sym).inspect}\n"
|
99
|
+
code << "end\n"
|
100
|
+
for parameter, convertor in @parameters.sort{|a,b| a[0].to_s <=> b[0].to_s}
|
101
|
+
# expr = "options.delete('#{@table.name}_#{parameter}') || options.delete('#{parameter}') || #{var_name(:params)}[:#{parameter}]"
|
102
|
+
# expr += " || #{@table.options[parameter]}" unless @table.options[parameter].blank?
|
103
|
+
# code << "#{var_name(:params)}[:#{parameter}] = (#{expr}).#{convertor}\n"
|
104
|
+
expr = "#{var_name(:params)}[:#{parameter}]"
|
105
|
+
expr = "(#{expr} || #{@table.options[parameter]})" unless @table.options[parameter].blank?
|
106
|
+
code << "#{var_name(:params)}[:#{parameter}] = #{expr}.#{convertor}\n"
|
107
|
+
end
|
108
|
+
# Order
|
109
|
+
code << "#{var_name(:order)} = #{@table.options[:order] ? @table.options[:order].inspect : 'nil'}\n"
|
110
|
+
code << "if #{var_name(:col)} = {" + @table.sortable_columns.collect{|c| "'#{c.sort_id}' => '#{c.sort_expression}'"}.join(', ') + "}[#{var_name(:params)}[:sort]]\n"
|
111
|
+
code << " #{var_name(:params)}[:dir] = 'asc' unless #{var_name(:params)}[:dir] == 'asc' or #{var_name(:params)}[:dir] == 'desc'\n"
|
112
|
+
code << " #{var_name(:order)} = #{var_name(:col)} + ' ' + #{var_name(:params)}[:dir]\n"
|
113
|
+
code << "end\n"
|
114
|
+
|
115
|
+
return code
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
require "active_list/generator/finder"
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
# Manage data query
|
4
|
+
class Generator
|
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] : @table.paginate?)
|
9
|
+
# Check order
|
10
|
+
unless @table.options.keys.include?(:order)
|
11
|
+
columns = @table.table_columns
|
12
|
+
@table.options[:order] = (columns.size > 0 ? columns.first.name.to_sym : {id: :desc}) # "#{@table.model.table_name}.id DESC"
|
13
|
+
end
|
14
|
+
|
15
|
+
class_name = @table.model.name
|
16
|
+
class_name = "(controller_name != '#{class_name.tableize}' ? controller_name.to_s.classify.constantize : #{class_name})" if self.collection?
|
17
|
+
|
18
|
+
# Find data
|
19
|
+
query_code = "#{class_name}"
|
20
|
+
query_code << self.scope_code if self.scope_code
|
21
|
+
query_code << ".select(#{self.select_code})" if self.select_code
|
22
|
+
query_code << ".where(#{self.conditions_code})" unless @table.options[:conditions].blank?
|
23
|
+
query_code << ".joins(#{@table.options[:joins].inspect})" unless @table.options[:joins].blank?
|
24
|
+
unless self.includes_reflections.empty?
|
25
|
+
expr = self.includes_reflections.inspect[1..-2]
|
26
|
+
query_code << ".includes(#{expr})"
|
27
|
+
query_code << ".references(#{expr})"
|
28
|
+
end
|
29
|
+
|
30
|
+
code = ""
|
31
|
+
code << "#{var_name(:count)} = #{query_code}.count\n"
|
32
|
+
if paginate
|
33
|
+
code << "#{var_name(:limit)} = (#{var_name(:params)}[:per_page] || 25).to_i\n"
|
34
|
+
code << "#{var_name(:page)} = (#{var_name(:params)}[:page] || 1).to_i\n"
|
35
|
+
code << "#{var_name(:page)} = 1 if #{var_name(:page)} < 1\n"
|
36
|
+
code << "#{var_name(:offset)} = (#{var_name(:page)} - 1) * #{var_name(:limit)}\n"
|
37
|
+
code << "#{var_name(:last)} = (#{var_name(:count)}.to_f / #{var_name(:limit)}).ceil.to_i\n"
|
38
|
+
code << "#{var_name(:last)} = 1 if #{var_name(:last)} < 1\n"
|
39
|
+
code << "return #{self.view_method_name}(options.merge(page: 1)) if 1 > #{var_name(:page)}\n"
|
40
|
+
code << "return #{self.view_method_name}(options.merge(page: #{var_name(:last)})) if #{var_name(:page)} > #{var_name(:last)}\n"
|
41
|
+
end
|
42
|
+
code << "#{self.records_variable_name} = #{query_code}"
|
43
|
+
code << ".reorder(#{var_name(:order)})"
|
44
|
+
if paginate
|
45
|
+
code << ".offset(#{var_name(:offset)})"
|
46
|
+
code << ".limit(#{var_name(:limit)})"
|
47
|
+
end
|
48
|
+
code << " || {}\n"
|
49
|
+
return code
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Compute includes Hash
|
55
|
+
def includes_reflections
|
56
|
+
hash = []
|
57
|
+
for column in @table.columns
|
58
|
+
if column.respond_to?(:reflection)
|
59
|
+
hash << column.reflection.name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
return hash
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def scope_code
|
67
|
+
return nil unless scopes = @table.options[:scope]
|
68
|
+
scopes = [scopes].flatten
|
69
|
+
code = ""
|
70
|
+
for scope in scopes
|
71
|
+
code << ".#{scope}"
|
72
|
+
end
|
73
|
+
return code
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Generate the code from a conditions option
|
78
|
+
def conditions_code
|
79
|
+
conditions = @table.options[:conditions]
|
80
|
+
code = ''
|
81
|
+
case conditions
|
82
|
+
when Array
|
83
|
+
case conditions[0]
|
84
|
+
when String # SQL
|
85
|
+
code << '[' + conditions.first.inspect
|
86
|
+
code << conditions[1..-1].collect{|p| ", " + sanitize_condition(p)}.join if conditions.size > 1
|
87
|
+
code << ']'
|
88
|
+
when Symbol # Method
|
89
|
+
raise "What?"
|
90
|
+
code << conditions.first.to_s + '('
|
91
|
+
code << conditions[1..-1].collect{|p| sanitize_condition(p)}.join(', ') if conditions.size > 1
|
92
|
+
code << ')'
|
93
|
+
else
|
94
|
+
raise ArgumentError.new("First element of an Array can only be String or Symbol.")
|
95
|
+
end
|
96
|
+
when Hash # SQL
|
97
|
+
code << '{' + conditions.collect{|key, value| key.to_s + ': ' + sanitize_condition(value)}.join(',') + '}'
|
98
|
+
when Symbol # Method
|
99
|
+
code << conditions.to_s + "(options)"
|
100
|
+
when Code
|
101
|
+
code << "(" + conditions.gsub(/\s*\n\s*/, ';') + ")"
|
102
|
+
when String
|
103
|
+
code << conditions.inspect
|
104
|
+
else
|
105
|
+
raise ArgumentError.new("Unsupported type for conditions: #{conditions.inspect}")
|
106
|
+
end
|
107
|
+
return code
|
108
|
+
end
|
109
|
+
|
110
|
+
def select_code
|
111
|
+
return nil unless @table.options[:distinct] or @table.options[:select]
|
112
|
+
code = ""
|
113
|
+
code << "DISTINCT " if @table.options[:distinct]
|
114
|
+
code << "#{@table.model.table_name}.*"
|
115
|
+
if @table.options[:select]
|
116
|
+
code << @table.options[:select].collect{|k, v| ", #{k[0].to_s+'.'+k[1].to_s} AS #{v}" }.join
|
117
|
+
end
|
118
|
+
return ("'" + code + "'").c
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def sanitize_condition(value)
|
123
|
+
# if value.is_a? Array
|
124
|
+
# # if value.size==1 and value[0].is_a? String
|
125
|
+
# # value[0].to_s
|
126
|
+
# # else
|
127
|
+
# value.inspect
|
128
|
+
# # end
|
129
|
+
# elsif value.is_a? Code
|
130
|
+
# value.inspect
|
131
|
+
# elsif value.is_a? String
|
132
|
+
# '"' + value.gsub('"', '\"') + '"'
|
133
|
+
# els
|
134
|
+
if [Date, DateTime].include? value.class
|
135
|
+
'"' + value.to_formatted_s(:db) + '"'
|
136
|
+
elsif value.is_a? NilClass
|
137
|
+
'nil'
|
138
|
+
else
|
139
|
+
value.inspect
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
|