active_list 7.0.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: '022092abfbb1ef56a9e935ba1f815b5f13dd7fc4'
4
- data.tar.gz: c15a78e14c48e10bfe281e2f735e5b3bc9084ea7
2
+ SHA256:
3
+ metadata.gz: 27436c5734c9477fdef8d87ba8d8baf417a3c6a63e74dcbe6461f02236139452
4
+ data.tar.gz: 9da5f80f7bd3617a7bb71dc0266c23c943180523a7f64ffa1d522afdc08f7b5e
5
5
  SHA512:
6
- metadata.gz: 51bed46ba112355efe2aadbeae3e652296fbe9071d63d915a73d4189b87c21b933c44b3af2eefc14032827bcf13e5e370f6310f6f30dc66c30ddbaf658330013
7
- data.tar.gz: edc59cfcb98fa9f621d67f1f6b593657ca2e1ede60c22631884c0ec749ed455e5ff0e8724c6559e2a2e8a915288d22311d8d72a6247aaea69687b7df29eb5fd5
6
+ metadata.gz: 6b1e434947929a963d81ad16c5fc34cae590f1010139da5862ad43aebc18f32ea946b378636c516939d7b2d0c6fa1074cf4e3a09364ebbabdbc6eef3cd85010e
7
+ data.tar.gz: e6344a3442a0c812667cd07ec35504e4545e526d4acb76bc27f02d4cbccf8205e52efccec42f8719a8f09bf25d0c3f8965ccc74b698e2a015a79f37904ccf2fc
@@ -158,6 +158,11 @@ ActiveList = {}
158
158
 
159
159
  # Select row
160
160
  $(document).on "click", "*[data-list-source] td>input[data-list-selector]", (event) ->
161
+ mainCheckbox = $("input[data-list-selector]").first()
162
+ someChecked = $("*[data-list-source] td>input[data-list-selector]:checked").length > 0
163
+ someUnchecked = $("*[data-list-source] td>input[data-list-selector]:not(:checked)").length > 0
164
+ mainCheckbox.prop("indeterminate", someChecked && someUnchecked);
165
+ mainCheckbox.prop("checked", someChecked || !someUnchecked);
161
166
  AL.select $(this)
162
167
  true
163
168
 
@@ -1,13 +1,14 @@
1
1
  module ActiveList
2
2
  module Definition
3
3
  class AbstractColumn
4
- attr_reader :table, :name, :id, :options
4
+ attr_reader :table, :name, :id, :options, :condition
5
5
 
6
6
  def initialize(table, name, options = {})
7
7
  @table = table
8
8
  @name = name.to_sym
9
9
  @options = options
10
10
  @hidden = !!@options.delete(:hidden)
11
+ @condition = @options.delete(:condition)
11
12
  @id = 'c' + @table.new_column_id # ActiveList.new_uid
12
13
  end
13
14
 
@@ -94,8 +94,8 @@ module ActiveList
94
94
  url[:redirect] ||= 'params[:redirect]'.c
95
95
  url.delete_if { |_k, v| v.nil? }
96
96
  cases << "#{record}.#{@name} == #{expected.inspect}\nlink_to(content_tag(:i) + h(#{url[:action].inspect}.t(scope: 'rest.actions'))"\
97
- ', {' + url.collect { |k, v| "#{k}: " + urlify(v, record) }.join(', ') + format + '}' \
98
- ", {class: '#{@name}'" + link_options + '}'\
97
+ ', {' + url.collect { |k, v| "#{k}: " + urlify(k, v, record) }.join(', ') + format + '}' \
98
+ ", {class: '#{@options[:icon_name] || @name}'" + link_options + '}'\
99
99
  ")\n"
100
100
  end
101
101
 
@@ -108,8 +108,8 @@ module ActiveList
108
108
  url[:id] = 'RECORD.id'.c if url[:id] == ID_PLACEHOLDER
109
109
  url[:redirect] ||= 'params[:redirect]'.c
110
110
  url.delete_if { |_k, v| v.nil? }
111
- url = '{' + url.collect { |k, v| "#{k}: " + urlify(v, record) }.join(', ') + format + '}'
112
- code = "{class: '#{@name}'" + link_options + '}'
111
+ url = '{' + url.collect { |k, v| "#{k}: " + urlify(k, v, record) }.join(', ') + format + '}'
112
+ code = "{class: '#{@options[:icon_name] || @name}'" + link_options + '}'
113
113
  code = "link_to(content_tag(:i) + h(' ' + :#{action}.t(scope: 'rest.actions')), " + url + ', ' + code + ')'
114
114
  end
115
115
  if @options[:if]
@@ -11,13 +11,7 @@ module ActiveList
11
11
  else
12
12
  @label_method.to_s.gsub('human_', '').to_sym
13
13
  end
14
- unless @sort_column = options[:sort]
15
- @sort_column = if @table.model.columns_hash[@label_method.to_s]
16
- @label_method
17
- elsif @table.model.columns_hash[@name.to_s]
18
- @name
19
- end
20
- end
14
+ @sort_column = get_sort_column
21
15
  @computation_method = options[:on_select]
22
16
  @column = @table.model.columns_hash[@label_method.to_s]
23
17
  end
@@ -51,9 +45,27 @@ module ActiveList
51
45
  code.c
52
46
  end
53
47
 
48
+ def get_sort_column
49
+ selects = @table.options[:select] || {}
50
+ selects_label = selects.find { |sql_name, name| name.to_s == @label_method.to_s }&.last
51
+ selects_name = selects.find { |sql_name, name| name.to_s == @name.to_s }&.last
52
+ if (selects_label || selects_name) && options[:sort].blank?
53
+ sort_column = (selects_label || selects_name)
54
+ else
55
+ sort_column = options[:sort]
56
+ sort_column ||= if @table.model.columns_hash[@label_method.to_s]
57
+ @label_method
58
+ elsif @table.model.columns_hash[@name.to_s]
59
+ @name
60
+ end
61
+ sort_column &&= "#{@table.model.table_name}.#{sort_column}"
62
+ end
63
+ sort_column
64
+ end
65
+
54
66
  # Returns the class name of the used model
55
67
  def class_name
56
- table.model.name
68
+ "RECORD.class.name.tableize".c
57
69
  end
58
70
 
59
71
  def sortable?
@@ -70,7 +82,7 @@ module ActiveList
70
82
  end
71
83
 
72
84
  def sort_expression
73
- "#{@table.model.table_name}.#{@sort_column}"
85
+ @sort_column
74
86
  end
75
87
  end
76
88
  end
@@ -22,11 +22,11 @@ module ActiveList
22
22
  currency = currency_for(record)
23
23
  datum = "(#{datum}.nil? ? '' : #{datum}.l(#{'currency: ' + currency.inspect if currency}))"
24
24
  elsif @name.to_s.match(/(^|\_)currency$/) && datatype == :string
25
- datum = "(Nomen::Currency[#{datum}] ? Nomen::Currency[#{datum}].human_name : '')"
25
+ datum = "(Onoma::Currency[#{datum}] ? Onoma::Currency[#{datum}].human_name : '')"
26
26
  elsif @name.to_s.match(/(^|\_)country$/) && datatype == :string
27
- datum = "(Nomen::Country[#{datum}] ? Nomen::Country[#{datum}].human_name : '')"
27
+ datum = "(Onoma::Country[#{datum}] ? Onoma::Country[#{datum}].human_name : '')"
28
28
  elsif @name.to_s.match(/(^|\_)language$/) && datatype == :string
29
- datum = "(Nomen::Language[#{datum}] ? Nomen::Language[#{datum}].human_name : '')"
29
+ datum = "(Onoma::Language[#{datum}] ? Onoma::Language[#{datum}].human_name : '')"
30
30
  elsif enumerize?
31
31
  datum = "(#{datum}.nil? ? '' : #{datum}.text)"
32
32
  end
@@ -1,6 +1,10 @@
1
1
  module ActiveList
2
2
  module Definition
3
3
  class EmptyColumn < AbstractColumn
4
+
5
+ def header_code
6
+ "#{name.to_s.strip.inspect}.t(scope: 'labels')".c
7
+ end
4
8
  end
5
9
  end
6
10
  end
@@ -1,6 +1,19 @@
1
1
  module ActiveList
2
2
  module Definition
3
3
  class StatusColumn < AttributeColumn
4
+ def initialize(table, name, options = {})
5
+ super
6
+
7
+ @tooltip_method = options.fetch(:tooltip_method, nil)
8
+ end
9
+
10
+ def tooltip_title_code(record, child)
11
+ c = if @tooltip_method.nil?
12
+ "#{record}.try(:human_status) || #{record}&.try(:human_state_name) || #{datum_value(record, child)}.to_s.capitalize"
13
+ else
14
+ "#{record}.#{@tooltip_method}"
15
+ end
16
+ end
4
17
  end
5
18
  end
6
19
  end
@@ -103,6 +103,10 @@ module ActiveList
103
103
  add :action, name, options
104
104
  end
105
105
 
106
+ # Add a new method in Table which permit to define empty columns
107
+ def empty(name, options = {})
108
+ add :empty, name, options
109
+ end
106
110
  # # Add a new method in Table which permit to define data columns
107
111
  # def attribute(name, options = {})
108
112
  # add :attribute, name, options
@@ -12,12 +12,39 @@ module ActiveList
12
12
  'txt'
13
13
  end
14
14
 
15
+ def file_name_code
16
+ "file_name = #{table.model.name}.model_name.human\n".c
17
+ end
18
+
15
19
  def mime_type
16
20
  Mime::TEXT
17
21
  end
18
22
 
23
+ def generate_file_code(format)
24
+ code = file_name_code
25
+ if generator.export_class
26
+ code << generator.exportable_query_code
27
+ code << "#{generator.export_class}.perform_later(user: current_user,\n"
28
+ code << " query: query,\n"
29
+ code << " content: #{columns_to_hash},\n"
30
+ code << " file_name: file_name,\n"
31
+ code << " format: '#{format}',\n"
32
+ code << " file_extension: '#{file_extension}')\n"
33
+ code << "notify_success(:document_in_preparation)\n"
34
+ code << "redirect_to(:back)\n"
35
+ else
36
+ code << generate_data_code
37
+ code << send_data_code
38
+ end
39
+ code.c
40
+ end
41
+
19
42
  def send_data_code
20
- raise NotImplementedError, "#{self.class.name}#format_data_code is not implemented."
43
+ raise NotImplementedError.new("#{self.class.name}#send_data_code must be implemented in sub-classes.")
44
+ end
45
+
46
+ def generate_data_code
47
+ raise NotImplementedError.new("#{self.class.name}#generate_data_code must be implemented in sub-classes.")
21
48
  end
22
49
 
23
50
  def columns_headers(options = {})
@@ -46,6 +73,12 @@ module ActiveList
46
73
  end
47
74
  array
48
75
  end
76
+
77
+ def columns_to_hash
78
+ table.exportable_columns.map do |column|
79
+ [column.header_code, column.exporting_datum_code('record').to_s]
80
+ end.to_h
81
+ end
49
82
  end
50
83
  end
51
84
  end
@@ -1,6 +1,7 @@
1
1
  module ActiveList
2
2
  module Exporters
3
3
  class CsvExporter < AbstractExporter
4
+
4
5
  def file_extension
5
6
  'csv'
6
7
  end
@@ -9,7 +10,7 @@ module ActiveList
9
10
  Mime[:csv]
10
11
  end
11
12
 
12
- def send_data_code
13
+ def generate_data_code
13
14
  record = 'r'
14
15
  code = generator.select_data_code(paginate: false)
15
16
  code << "data = ::CSV.generate do |csv|\n"
@@ -18,9 +19,12 @@ module ActiveList
18
19
  code << " csv << [#{columns_to_array(:body, record: record).join(', ')}]\n"
19
20
  code << " end\n"
20
21
  code << "end\n"
21
- code << "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_') + '.#{file_extension}')\n"
22
22
  code.c
23
23
  end
24
+
25
+ def send_data_code
26
+ "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: file_name.parameterize + '.#{file_extension}')\n".c
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -4,6 +4,7 @@ Mime::Type.register('text/csv', :xcsv) unless defined? Mime::XCSV
4
4
  module ActiveList
5
5
  module Exporters
6
6
  class ExcelCsvExporter < CsvExporter
7
+
7
8
  def file_extension
8
9
  'csv'
9
10
  end
@@ -12,7 +13,7 @@ module ActiveList
12
13
  Mime[:xcsv]
13
14
  end
14
15
 
15
- def send_data_code
16
+ def generate_data_code
16
17
  record = 'r'
17
18
  code = generator.select_data_code(paginate: false)
18
19
  encoding = 'CP1252'
@@ -22,7 +23,6 @@ module ActiveList
22
23
  code << " csv << [#{columns_to_array(:body, record: record, encoding: encoding).join(', ')}]\n"
23
24
  code << " end\n"
24
25
  code << "end\n"
25
- code << "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')+'.#{file_extension}')\n"
26
26
  code.c
27
27
  end
28
28
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'zip'
3
+ require 'rodf'
4
4
 
5
5
  # Register ODS format unless is already set
6
6
  Mime::Type.register('application/vnd.oasis.opendocument.spreadsheet', :ods) unless defined? Mime::ODS
@@ -8,11 +8,6 @@ Mime::Type.register('application/vnd.oasis.opendocument.spreadsheet', :ods) unle
8
8
  module ActiveList
9
9
  module Exporters
10
10
  class OpenDocumentSpreadsheetExporter < AbstractExporter
11
- DATE_ELEMENTS = {
12
- 'm' => '<number:month number:style="long"/>',
13
- 'd' => '<number:day number:style="long"/>',
14
- 'Y' => '<number:year/>'
15
- }.freeze
16
11
 
17
12
  def file_extension
18
13
  'ods'
@@ -22,55 +17,42 @@ module ActiveList
22
17
  Mime[:ods]
23
18
  end
24
19
 
25
- def send_data_code
26
- xml_escape = "to_s.gsub('&', '&amp;').gsub('\\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')"
27
- xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
20
+ def generate_data_code
28
21
  record = 'r'
29
- code = generator.select_data_code(paginate: false)
30
- code << "name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_')\n"
31
- code << "file = ActiveList.temporary_directory.join(name + rand(999_999_999).to_s(36) + '.#{file_extension}')\n"
32
- code << "FileUtils.mkdir_p(file.dirname)\n"
33
- code << "Zip::OutputStream.open(file) do |zile|\n"
34
- # MimeType in first place
35
- code << " zile.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)\n"
36
- code << " zile << '#{mime_type}'\n"
37
-
38
- # Manifest
39
- code << " zile.put_next_entry('META-INF/manifest.xml')\n"
40
- 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=\"#{mime_type}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>')\n"
41
- code << " zile.put_next_entry('content.xml')\n"
42
22
 
43
- 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"
44
- # Styles
45
- code << " zile << ('<office:automatic-styles>"\
46
- '<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>'\
47
- '<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>'\
48
- '<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"/>'\
49
- "</office:automatic-styles>')\n"
23
+ code = generator.select_data_code(paginate: false)
24
+ code << <<~RUBY
25
+ records = #{generator.records_variable_name}
26
+ data = RODF::Spreadsheet.new
27
+
28
+ data.instance_eval do
29
+ office_style :head, family: :cell do
30
+ property :text, 'font-weight': :bold
31
+ property :paragraph, 'text-align': :center
32
+ end
33
+
34
+ table #{table.model.name}.model_name.human do
35
+ row do
36
+ #{columns_to_array(:header)}.each do |header|
37
+ cell header, style: :head
38
+ end
39
+ end
40
+
41
+ for #{record} in records
42
+ row do
43
+ #{columns_to_array(:body, record: record)}.each do |value|
44
+ cell value
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ RUBY
51
+ code.c
52
+ end
50
53
 
51
- # Tables
52
- code << " zile << ('<office:body><office:spreadsheet><table:table table:name=\"'+#{table.model.name}.model_name.human.#{xml_escape}+'\">')\n"
53
- code << " zile << ('<table:table-column table:number-columns-repeated=\"#{table.exportable_columns.size}\"/>')\n"
54
- 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"
55
- code << " for #{record} in #{generator.records_variable_name}\n"
56
- code << " zile << ('<table:table-row>" + table.exportable_columns.collect do |column|
57
- '<table:table-cell' + (if column.numeric? || column.datatype == :decimal
58
- " office:value-type=\"float\" office:value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
59
- elsif column.datatype == :boolean
60
- " office:value-type=\"boolean\" office:boolean-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
61
- elsif column.datatype == :date
62
- " office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
63
- else
64
- ' office:value-type="string"'
65
- end) + "><text:p>'+(" + column.exporting_datum_code(record, true) + ").#{xml_escape}+'</text:p></table:table-cell>"
66
- end.join + "</table:table-row>')\n"
67
- code << " end\n"
68
- code << " zile << ('</table:table></office:spreadsheet></office:body></office:document-content>')\n"
69
- code << "end\n"
70
- code << "send_file(file, stream: false, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: name+'.#{file_extension}')\n"
71
- # code << "File.delete(file)\n" # Removes tmp files before they explode the disk
72
- # raise code
73
- code
54
+ def send_data_code
55
+ "send_data(data.bytes, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: file_name.parameterize + '.#{file_extension}')\n".c
74
56
  end
75
57
  end
76
58
  end
@@ -1,17 +1,18 @@
1
1
  module ActiveList
2
2
  class Generator
3
- attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name
3
+ attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name, :export_class
4
4
 
5
5
  def initialize(*args, &_block)
6
6
  options = args.extract_options!
7
7
  @controller = options[:controller]
8
8
  name = args.shift || @controller.controller_name.to_sym
9
9
  model = (options[:model] || name).to_s.classify.constantize
10
- @collection = !!(model.name == @controller.controller_name.to_s.classify)
10
+ @collection = options[:collection] || !!(model.name == @controller.controller_name.to_s.classify)
11
11
  @controller_method_name = "list#{'_' + name.to_s if name != @controller.controller_name.to_sym}"
12
12
  @view_method_name = "_#{@controller.controller_name}_list_#{name}_tag"
13
13
  @records_variable_name = "@#{name}"
14
14
  @table = ActiveList::Definition::Table.new(name, model, options)
15
+ @export_class = options[:export_class]
15
16
  if block_given?
16
17
  yield @table
17
18
  else
@@ -47,7 +48,7 @@ module ActiveList
47
48
  code << " end\n"
48
49
  for format, exporter in ActiveList::Exporters.hash
49
50
  code << " format.#{format} do\n"
50
- code << exporter.new(self).send_data_code.dig(3)
51
+ code << exporter.new(self).generate_file_code(format).dig(3)
51
52
  code << " end\n"
52
53
  end
53
54
  code << " end\n"
@@ -10,8 +10,8 @@ module ActiveList
10
10
  @table.options[:order] = (columns.any? ? columns.first.name.to_sym : { id: :desc })
11
11
  end
12
12
 
13
- class_name = @table.model.name
14
- class_name = "(controller_name != '#{class_name.tableize}' ? controller_name.to_s.classify.constantize : #{class_name})" if collection?
13
+ class_name = "options[\"constant_name\"]&.constantize || #{@table.model.name}"
14
+ class_name = "(controller_name != '#{class_name.tableize}' && !options[\"constant_name\"] ? controller_name.to_s.classify.constantize : #{class_name})" if collection?
15
15
 
16
16
  # Find data
17
17
  query_code = class_name.to_s
@@ -34,7 +34,6 @@ module ActiveList
34
34
  else
35
35
  "#{var_name(:count)} = #{query_code}.count\n"
36
36
  end
37
-
38
37
  query_code << ".group(#{@table.options[:group].inspect})" unless @table.options[:group].blank?
39
38
  query_code << ".reorder(#{var_name(:order)})"
40
39
 
@@ -65,6 +64,64 @@ module ActiveList
65
64
  code
66
65
  end
67
66
 
67
+ def exportable_query_code(options = {})
68
+ unless @table.options.keys.include?(:order)
69
+ columns = @table.table_columns
70
+ @table.options[:order] = (columns.any? ? columns.first.name.to_sym : { id: :desc })
71
+ end
72
+
73
+ class_name = "options[\"constant_name\"]&.constantize || #{@table.model.name}"
74
+ class_name = "(controller_name != '#{class_name.tableize}' && !options[\"constant_name\"] ? controller_name.to_s.classify.constantize : #{class_name})" if collection?
75
+
76
+ code = ''
77
+
78
+ code << "query = #{class_name}.to_s\n"
79
+ code << "query << #{scope_code.inspect}\n" if scope_code
80
+
81
+ if select_code
82
+ code << "select = #{select_code}\n"
83
+ code << "query << \".select(\"\n"
84
+ code << "query << select.inspect\n"
85
+ code << "query << \")\"\n"
86
+ end
87
+
88
+ if from_code
89
+ code << "from = #{from_code}\n"
90
+ code << "query << \".from(\"\n"
91
+ code << "query << from.inspect\n"
92
+ code << "query << \")\"\n"
93
+ end
94
+
95
+ unless @table.options[:conditions].blank?
96
+ code << "condition = #{conditions_code}\n"
97
+ code << "query << \".where(\"\n"
98
+ code << "query << condition.inspect\n"
99
+ code << "query << \")\"\n"
100
+ end
101
+
102
+ code << "query << \".joins(#{@table.options[:joins].inspect})\"\n" unless @table.options[:joins].blank?
103
+
104
+ unless includes_reflections.empty?
105
+ expr = includes_reflections.inspect[1..-2]
106
+ code << "query << \".includes(#{expr})\"\n"
107
+ code << "query << \".references(#{expr})\"\n"
108
+ end
109
+
110
+ unless @table.options[:group].blank?
111
+ code << "group = #{@table.options[:group].inspect}\n"
112
+ code << "query << \".group(\"\n"
113
+ code << "query << group.inspect\n"
114
+ code << "query << \")\"\n"
115
+ end
116
+
117
+ code << "order = #{var_name(:order)}\n"
118
+ code << "query << \".reorder(\"\n"
119
+ code << "query << order.inspect\n"
120
+ code << "query << \")\"\n"
121
+
122
+ code.c
123
+ end
124
+
68
125
  protected
69
126
 
70
127
  # Compute includes Hash
@@ -133,7 +190,7 @@ module ActiveList
133
190
  code << 'DISTINCT ' if @table.options[:distinct]
134
191
  if @table.options[:select]
135
192
  # code << @table.options[:select].collect { |k, v| ", #{k[0].to_s + '.' + k[1].to_s} AS #{v}" }.join
136
- code << @table.options[:select].collect do |k, v|
193
+ code << @table.options[:select].collect do |k, v|
137
194
  c = if k.is_a? Array
138
195
  k[0].to_s + '.' + k[1].to_s
139
196
  else
@@ -145,7 +202,7 @@ module ActiveList
145
202
  else
146
203
  code << "#{@table.model.table_name}.*"
147
204
  end
148
- ("'" + code + "'").c
205
+ ('"' + code + '"').c
149
206
  end
150
207
 
151
208
  def sanitize_condition(value)
@@ -20,11 +20,12 @@ module ActiveList
20
20
  end
21
21
  end
22
22
 
23
- def urlify(value, record_name)
24
- if value.is_a?(CodeString)
25
- '(' + value.gsub(/RECORD/, record_name) + ')'
23
+ def urlify(key, value, record_name, namespace = nil)
24
+ return value.inspect unless value.is_a?(CodeString)
25
+ if key == :controller && namespace
26
+ '(' + "'/#{namespace}/' + " + value.gsub(/RECORD/, record_name) + ')'
26
27
  else
27
- value.inspect
28
+ '(' + value.gsub(/RECORD/, record_name) + ')'
28
29
  end
29
30
  end
30
31
  end
@@ -41,7 +41,7 @@ module ActiveList
41
41
  header = header_code
42
42
  extras = extras_codes
43
43
 
44
- code = generator.select_data_code
44
+ code = "#{generator.select_data_code}(options)\n"
45
45
  # Hack for Rails 5
46
46
  code << "__params = params.permit!\n"
47
47
  code << "#{var_name(:tbody)} = '<tbody data-total=\"' + #{var_name(:count)}.to_s + '\""
@@ -53,7 +53,12 @@ module ActiveList
53
53
  code << "if #{var_name(:count)} > 0\n"
54
54
  code << " #{generator.records_variable_name}.each do |#{record}|\n"
55
55
  code << " #{var_name(:attrs)} = {id: 'r' + #{record}.id.to_s}\n"
56
- code << " #{var_name(:attrs)}['data-' + options[:data].gsub('_', '-')] = #{record}.send(options[:data]) if options[:data]\n"
56
+ code << " if #{var_name(:params)}[:data]\n"
57
+ code << " #{var_name(:params)}[:data] = [#{var_name(:params)}[:data]] unless #{var_name(:params)}[:data].is_a?(Array)\n"
58
+ code << " #{var_name(:params)}[:data].each do |attr|\n"
59
+ code << " #{var_name(:attrs)}['data-' + attr.gsub('_', '-')] = #{record}.send(attr)\n"
60
+ code << " end\n"
61
+ code << " end\n"
57
62
  if table.options[:line_class]
58
63
  code << " #{var_name(:attrs)}[:class] = (#{recordify!(table.options[:line_class], record)}).to_s\n"
59
64
  code << " #{var_name(:attrs)}[:class] << ' focus' if __params['#{table.name}-id'].to_i == #{record}.id\n"
@@ -165,17 +170,20 @@ module ActiveList
165
170
  children_mode = !!(nature == :children)
166
171
  for column in table.columns
167
172
  value_code = ''
173
+ title_value_code = ''
168
174
  if column.is_a? ActiveList::Definition::EmptyColumn
169
175
  value_code = 'nil'
170
176
  elsif column.is_a? ActiveList::Definition::StatusColumn
171
-
177
+ title_value_code = nil
172
178
  value_code = column.datum_code(record, children_mode)
179
+ title_code = column.tooltip_title_code(record, children_mode)
173
180
  levels = %w[go caution stop]
174
181
  lights = levels.collect do |light|
175
182
  "content_tag(:span, '', :class => #{light.inspect})"
176
183
  end.join(' + ')
177
184
  # Expected value are :valid, :warning, :error
178
- value_code = "content_tag(:span, #{lights}, :class => 'lights lights-' + (#{levels.inspect}.include?(#{value_code}.to_s) ? #{value_code}.to_s : 'undefined'))"
185
+
186
+ value_code = "content_tag(:span, #{lights}, :class => 'lights lights-' + (#{levels.inspect}.include?(#{value_code}.to_s) ? #{value_code}.to_s : 'undefined'), data: { toggle: :tooltip, placement: :top }, title: #{title_code})"
179
187
 
180
188
  elsif column.is_a? ActiveList::Definition::DataColumn
181
189
  if column.options[:children].is_a?(FalseClass) && children_mode
@@ -183,6 +191,7 @@ module ActiveList
183
191
  else
184
192
  value_code = column.datum_code(record, children_mode)
185
193
  if column.datatype == :boolean
194
+ title_value_code = value_code
186
195
  value_code = "content_tag(:div, '', :class => 'checkbox-'+(" + value_code.to_s + " ? 'true' : 'false'))"
187
196
  elsif %i[date datetime timestamp measure].include? column.datatype
188
197
  value_code = "(#{value_code}.nil? ? '' : #{value_code}.l)"
@@ -204,29 +213,37 @@ module ActiveList
204
213
  column.options[:url] = {} unless column.options[:url].is_a?(Hash)
205
214
  column.options[:url][:id] ||= (column.record_expr(record) + '.id').c
206
215
  column.options[:url][:action] ||= :show
207
- column.options[:url][:controller] ||= column.class_name.tableize.to_sym # (self.generator.collection? ? "RECORD.class.name.tableize".c : column.class_name.tableize.to_sym)
208
- # column.options[:url][:controller] ||= "#{value_code}.class.name.tableize".c
209
- url = column.options[:url].collect { |k, v| "#{k}: " + urlify(v, record) }.join(', ')
216
+ default_controller = column.class_name.is_a?(CodeString) ? column.class_name : column.class_name.tableize.to_sym
217
+ column.options[:url][:controller] ||= default_controller
218
+ namespace = column.options[:url].delete(:namespace)
219
+ url = column.options[:url].collect { |k, v| "#{k}: " + urlify(k, v, record, namespace) }.join(', ')
220
+
221
+ title_value_code = value_code
210
222
  value_code = "(#{value_code}.blank? ? '' : link_to(#{value_code}.to_s, #{url}))"
211
223
  elsif column.options[:mode] || column.label_method == :email
224
+ title_value_code = value_code
212
225
  value_code = "(#{value_code}.blank? ? '' : mail_to(#{value_code}))"
213
226
  elsif column.options[:mode] || column.label_method == :website
227
+ title_value_code = value_code
214
228
  value_code = "(#{value_code}.blank? ? '' : link_to(" + value_code + ', ' + value_code + '))'
215
229
  elsif column.label_method == :color
230
+ title_value_code = value_code
216
231
  value_code = "content_tag(:div, #{column.datum_code(record)}, style: 'background: #'+" + column.datum_code(record) + ')'
217
232
  elsif column.label_method.to_s.match(/(^|\_)currency$/) && column.datatype == :string
218
- value_code = "(Nomen::Currency[#{value_code}] ? Nomen::Currency[#{value_code}].human_name : #{value_code})"
233
+ value_code = "(Onoma::Currency[#{value_code}] ? Onoma::Currency[#{value_code}].human_name : #{value_code})"
219
234
  elsif column.label_method.to_s.match(/(^|\_)language$/) && column.datatype == :string
220
- value_code = "(Nomen::Language[#{value_code}] ? Nomen::Language[#{value_code}].human_name : #{value_code})"
235
+ value_code = "(Onoma::Language[#{value_code}] ? Onoma::Language[#{value_code}].human_name : #{value_code})"
221
236
  elsif column.label_method.to_s.match(/(^|\_)country$/) && column.datatype == :string
222
- value_code = "(Nomen::Country[#{value_code}] ? (image_tag('countries/' + #{value_code}.to_s + '.png') + ' ' + Nomen::Country[#{value_code}].human_name).html_safe : #{value_code})"
237
+ value_code = "(Onoma::Country[#{value_code}] ? (image_tag('countries/' + #{value_code}.to_s + '.png') + ' ' + Onoma::Country[#{value_code}].human_name).html_safe : #{value_code})"
223
238
  else # if column.datatype == :string
224
239
  value_code = "h(#{value_code}.to_s)"
240
+ title_value_code = nil
225
241
  end
226
242
 
227
243
  value_code = "if #{record}\n#{value_code.dig}end" if column.is_a?(ActiveList::Definition::AssociationColumn)
228
244
  end
229
245
  elsif column.is_a?(ActiveList::Definition::CheckBoxColumn)
246
+ title_value_code = nil
230
247
  if nature == :body
231
248
  form_name = column.form_name || "'#{table.name}[' + #{record}.id.to_s + '][#{column.name}]'".c
232
249
  value = 'nil'
@@ -241,15 +258,26 @@ module ActiveList
241
258
  value_code << 'nil'
242
259
  end
243
260
  elsif column.is_a?(ActiveList::Definition::TextFieldColumn)
261
+ title_value_code = nil
244
262
  form_name = column.form_name || "'#{table.name}[' + #{record}.id.to_s + '][#{column.name}]'".c
245
263
  value_code = (nature == :body ? "text_field_tag(#{form_name.inspect}, #{recordify!(column.options[:value] || column.name, record)}#{column.options[:size] ? ', size: ' + column.options[:size].to_s : ''})" : 'nil') # , id: '#{table.name}_'+#{record}.id.to_s + '_#{column.name}'
246
264
  elsif column.is_a?(ActiveList::Definition::ActionColumn)
265
+ title_value_code = nil
247
266
  next unless column.use_single?
248
267
  value_code = (nature == :body ? column.operation(record) : 'nil')
249
268
  else
250
269
  value_code = "'&#160;&#8709;&#160;'.html_safe"
251
270
  end
252
- code << "content_tag(:td, :class => \"#{column_classes(column)}\","
271
+
272
+ title_attr_code = if title_value_code.nil?
273
+ ''
274
+ elsif title_value_code.blank?
275
+ ":title => (#{value_code}),"
276
+ else
277
+ ":title => (#{title_value_code}),"
278
+ end
279
+
280
+ code << "content_tag(:td, #{title_attr_code} :class => \"#{column_classes(column)}\","
253
281
  code << " data: { 'list-column-header' => '#{column.short_id}'"
254
282
  code << ", 'list-cell-value' => \"\#{#{column.datum_value(record, children_mode)}.to_f}\"" if column.computable?
255
283
  code << " } ) do\n"
@@ -314,7 +342,7 @@ module ActiveList
314
342
  end
315
343
  table.columns.each do |column|
316
344
  next if column.is_a?(ActiveList::Definition::ActionColumn) && !column.use_single?
317
- code << "<th data-list-column=\"#{column.sort_id}\""
345
+ code << "<th data-list-column=\"#{column.options[:icon_name] || column.sort_id}\""
318
346
  code << " data-list-column-cells=\"#{column.short_id}\""
319
347
  code << " data-list-column-sort=\"'+(#{var_name(:params)}[:sort] != '#{column.sort_id}' ? 'asc' : #{var_name(:params)}[:dir] == 'asc' ? 'desc' : 'asc')+'\"" if column.sortable?
320
348
  code << " data-list-column-computation=\"#{column.computation_method}\"" if column.computable?
@@ -322,8 +350,8 @@ module ActiveList
322
350
  unit = "''"
323
351
  precision = "''"
324
352
  if column.options[:currency]
325
- unit = "Nomen::Currency.find(#{column.currency_for(generator.records_variable_name + '.first').inspect} || 'EUR').symbol.to_s"
326
- precision = "Nomen::Currency.find(#{column.currency_for(generator.records_variable_name + '.first').inspect} || 'EUR').precision.to_s"
353
+ unit = "Onoma::Currency.find(#{column.currency_for(generator.records_variable_name + '.first').inspect} || 'EUR').symbol.to_s"
354
+ precision = "Onoma::Currency.find(#{column.currency_for(generator.records_variable_name + '.first').inspect} || 'EUR').precision.to_s"
327
355
  elsif column.computable?
328
356
  unit = "#{generator.records_variable_name}.first.#{column.value_method}.symbol"
329
357
  precision = "'2'"
@@ -424,7 +452,11 @@ module ActiveList
424
452
  classes = []
425
453
  conds = []
426
454
  conds << [:sor, "#{var_name(:params)}[:sort] == '#{column.sort_id}'".c] if column.sortable?
427
- conds << [:hidden, "#{var_name(:params)}[:hidden_columns].include?(:#{column.name})".c] if column.is_a? ActiveList::Definition::DataColumn
455
+ if column.is_a? ActiveList::Definition::DataColumn
456
+ conds << [:hidden, "#{var_name(:params)}[:hidden_columns].include?(:#{column.name})".c]
457
+ elsif column.condition
458
+ conds << [:hidden, "h(#{column.condition}) == 'false'".c]
459
+ end
428
460
  classes << column.options[:class].to_s.strip unless column.options[:class].blank?
429
461
  classes << column.short_id unless without_id
430
462
  if column.is_a? ActiveList::Definition::ActionColumn
@@ -1,3 +1,3 @@
1
1
  module ActiveList
2
- VERSION = '7.0.0'.freeze
2
+ VERSION = '8.1.0'.freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  source 'https://rubygems.org'
2
+ git_source(:gitlab) { |repo_name| "https://gitlab.com/#{repo_name}.git" }
2
3
 
3
4
  gem 'rails', '~> 5.0'
4
5
 
@@ -8,6 +9,10 @@ gem 'rails', '~> 5.0'
8
9
  gem 'sqlite3', '~> 1.3.6'
9
10
  gem 'active_list', path: '../..'
10
11
 
12
+ gem 'sprockets', '< 4'
13
+
14
+ gem 'onoma', gitlab: 'ekylibre/onoma'
15
+
11
16
  # Gems used only for assets and not required
12
17
  # in production environments by default.
13
18
  group :assets do
@@ -39,6 +39,7 @@ module Dummy
39
39
  # Configure sensitive parameters which will be filtered from the log file.
40
40
  config.filter_parameters += [:password]
41
41
 
42
+ config.active_record.sqlite3.represent_boolean_as_integer = true
42
43
  # Use SQL instead of Active Record's schema dumper when creating the database.
43
44
  # This is necessary if your schema can't be completely dumped by the schema dumper,
44
45
  # like if you have constraints or database-specific column types
@@ -5,4 +5,3 @@
5
5
  # Make sure the secret is at least 30 characters and all random,
6
6
  # no regular words or you'll be exposed to dictionary attacks.
7
7
  Dummy::Application.config.secret_key_base = '7a06e73398090c095bed02f2dff3808b043e50cb928f7b7bfd02faadd988a0d9cf31dfc74d1bf661ac94c8d0d73c8ceb4d98210d09f251f0c6d70f09923db784'
8
- Dummy::Application.config.secret_token = '7a06e73398090c095bed02f2dff3808b043e50cb928f7b7bfd02faadd988a0d9cf31dfc74d1bf661ac94c8d0d73c8ceb4d98210d09f251f0c6d70f09923db784'
@@ -41,7 +41,7 @@ end
41
41
 
42
42
  module ActionView
43
43
  class Base
44
- module Nomen
44
+ module Onoma
45
45
  class Currencies
46
46
  def self.[](_)
47
47
  klass = Struct.const_defined?(:Currency) ? Struct::Currency : Struct.new('Currency', :precision, :symbol)
metadata CHANGED
@@ -1,91 +1,119 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 8.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brice Texier
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-01 00:00:00.000000000 Z
11
+ date: 2020-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: arel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '6'
19
+ version: 5.0.0
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: '3.2'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '6'
26
+ version: 5.0.0
33
27
  - !ruby/object:Gem::Dependency
34
- name: arel
28
+ name: code_string
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: 5.0.0
33
+ version: 0.0.1
40
34
  type: :runtime
41
35
  prerelease: false
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
38
  - - ">="
45
39
  - !ruby/object:Gem::Version
46
- version: 5.0.0
40
+ version: 0.0.1
47
41
  - !ruby/object:Gem::Dependency
48
- name: code_string
42
+ name: i18n-complements
49
43
  requirement: !ruby/object:Gem::Requirement
50
44
  requirements:
51
45
  - - ">="
52
46
  - !ruby/object:Gem::Version
53
- version: 0.0.1
47
+ version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
51
  requirements:
58
52
  - - ">="
59
53
  - !ruby/object:Gem::Version
60
- version: 0.0.1
54
+ version: '0'
61
55
  - !ruby/object:Gem::Dependency
62
- name: rubyzip
56
+ name: onoma
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rails
63
71
  requirement: !ruby/object:Gem::Requirement
64
72
  requirements:
65
73
  - - ">="
66
74
  - !ruby/object:Gem::Version
67
- version: '1.0'
75
+ version: '3.2'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '6'
68
79
  type: :runtime
69
80
  prerelease: false
70
81
  version_requirements: !ruby/object:Gem::Requirement
71
82
  requirements:
72
83
  - - ">="
73
84
  - !ruby/object:Gem::Version
74
- version: '1.0'
85
+ version: '3.2'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '6'
75
89
  - !ruby/object:Gem::Dependency
76
- name: i18n-complements
90
+ name: rodf
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.1'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.1'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rubyzip
77
105
  requirement: !ruby/object:Gem::Requirement
78
106
  requirements:
79
107
  - - ">="
80
108
  - !ruby/object:Gem::Version
81
- version: '0'
109
+ version: '1.0'
82
110
  type: :runtime
83
111
  prerelease: false
84
112
  version_requirements: !ruby/object:Gem::Requirement
85
113
  requirements:
86
114
  - - ">="
87
115
  - !ruby/object:Gem::Version
88
- version: '0'
116
+ version: '1.0'
89
117
  - !ruby/object:Gem::Dependency
90
118
  name: sqlite3
91
119
  requirement: !ruby/object:Gem::Requirement
@@ -208,11 +236,11 @@ files:
208
236
  - test/people_controller_test.rb
209
237
  - test/table_test.rb
210
238
  - test/test_helper.rb
211
- homepage: http://github.com/ekylibre/active_list
239
+ homepage: http://gitlab.com/ekylibre/active_list
212
240
  licenses:
213
241
  - MIT
214
242
  metadata: {}
215
- post_install_message:
243
+ post_install_message:
216
244
  rdoc_options: []
217
245
  require_paths:
218
246
  - lib
@@ -227,9 +255,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
255
  - !ruby/object:Gem::Version
228
256
  version: '0'
229
257
  requirements: []
230
- rubyforge_project:
231
- rubygems_version: 2.6.14
232
- signing_key:
258
+ rubygems_version: 3.0.3
259
+ signing_key:
233
260
  specification_version: 4
234
261
  summary: Simple interactive tables for Rails app
235
262
  test_files: