active-list 4.2.4 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/VERSION +1 -1
  3. data/{lib → app}/assets/images/active-list.png +0 -0
  4. data/app/assets/images/active-list.svg +415 -0
  5. data/{lib/assets/javascripts/active-list.jquery.js → app/assets/javascripts/active_list.jquery.js} +2 -2
  6. data/app/assets/stylesheets/active_list.css.scss +7 -0
  7. data/{lib/active-list/compass/stylesheets/active-list/_background.scss → app/assets/stylesheets/active_list/background.scss} +10 -8
  8. data/{lib/active-list/compass/stylesheets/active-list/_minimal.scss → app/assets/stylesheets/active_list/minimal.scss} +16 -16
  9. data/{lib/active-list/compass/stylesheets/active-list/_theme.scss → app/assets/stylesheets/active_list/theme.scss} +37 -37
  10. data/lib/active-list.rb +1 -37
  11. data/lib/active_list.rb +43 -0
  12. data/lib/active_list/action_pack.rb +46 -0
  13. data/lib/active_list/definition.rb +17 -0
  14. data/lib/active_list/definition/abstract_column.rb +54 -0
  15. data/lib/active_list/definition/action_column.rb +76 -0
  16. data/lib/active_list/definition/association_column.rb +80 -0
  17. data/lib/active_list/definition/attribute_column.rb +58 -0
  18. data/lib/active_list/definition/check_box_column.rb +17 -0
  19. data/lib/active_list/definition/data_column.rb +88 -0
  20. data/lib/active_list/definition/empty_column.rb +10 -0
  21. data/lib/active_list/definition/field_column.rb +20 -0
  22. data/lib/active_list/definition/status_column.rb +10 -0
  23. data/lib/active_list/definition/table.rb +159 -0
  24. data/lib/active_list/definition/text_field_column.rb +10 -0
  25. data/lib/active_list/exporters.rb +28 -0
  26. data/lib/active_list/exporters/abstract_exporter.rb +55 -0
  27. data/lib/active_list/exporters/csv_exporter.rb +32 -0
  28. data/lib/active_list/exporters/excel_csv_exporter.rb +38 -0
  29. data/lib/active_list/exporters/open_document_spreadsheet_exporter.rb +82 -0
  30. data/lib/active_list/generator.rb +122 -0
  31. data/lib/active_list/generator/finder.rb +150 -0
  32. data/lib/active_list/helpers.rb +33 -0
  33. data/lib/{active-list → active_list}/rails/engine.rb +3 -2
  34. data/lib/active_list/renderers.rb +25 -0
  35. data/lib/active_list/renderers/abstract_renderer.rb +29 -0
  36. data/lib/active_list/renderers/simple_renderer.rb +356 -0
  37. metadata +74 -55
  38. data/lib/active-list/action_pack.rb +0 -48
  39. data/lib/active-list/columns/action_column.rb +0 -83
  40. data/lib/active-list/columns/data_column.rb +0 -151
  41. data/lib/active-list/columns/field_column.rb +0 -29
  42. data/lib/active-list/compass/stylesheets/_active-list.scss +0 -7
  43. data/lib/active-list/definition.rb +0 -103
  44. data/lib/active-list/exporters.rb +0 -71
  45. data/lib/active-list/exporters/csv_exporter.rb +0 -30
  46. data/lib/active-list/exporters/excel_csv_exporter.rb +0 -36
  47. data/lib/active-list/exporters/open_document_spreadsheet_exporter.rb +0 -81
  48. data/lib/active-list/finder.rb +0 -134
  49. data/lib/active-list/generator.rb +0 -88
  50. data/lib/active-list/renderers.rb +0 -28
  51. data/lib/active-list/renderers/simple_renderer.rb +0 -335
  52. data/lib/assets/stylesheets/active-list.css.scss +0 -7
@@ -0,0 +1,54 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class AbstractColumn
6
+ attr_reader :table, :name, :id, :options
7
+
8
+ def initialize(table, name, options = {})
9
+ @table = table
10
+ @name = name.to_sym
11
+ @options = options
12
+ @hidden = !!@options.delete(:hidden)
13
+ @id = ActiveList.new_uid
14
+ end
15
+
16
+ def header_code
17
+ raise NotImplementedError, "#{self.class.name}#header_code is not implemented."
18
+ end
19
+
20
+ def hidden?
21
+ @hidden
22
+ end
23
+
24
+ def sortable?
25
+ false
26
+ end
27
+
28
+ def exportable?
29
+ false
30
+ end
31
+
32
+ # Unique identifier of the column in the application
33
+ def unique_id
34
+ "#{@table.name}-#{@name}"
35
+ end
36
+
37
+ # Uncommon but simple identifier for CSS class uses
38
+ def short_id
39
+ @id
40
+ end
41
+
42
+ alias :sort_id :name
43
+
44
+ def check_options!(options, *keys)
45
+ for key in options.keys
46
+ raise ArgumentError, "Key :#{key} is unexpected. (Expecting: #{keys.to_sentence})"
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,76 @@
1
+ # coding: utf-8
2
+ module ActiveList
3
+
4
+ module Definition
5
+
6
+ class ActionColumn < AbstractColumn
7
+ include ActiveList::Helpers
8
+
9
+ def header_code
10
+ "''".c
11
+ end
12
+
13
+ def operation(record = 'record_of_the_death')
14
+ @options[:method] = :delete if @name.to_s == "destroy" and !@options.has_key?(:method)
15
+ @options[:confirm] ||= :are_you_sure_you_want_to_delete if @name.to_s == "destroy" and !@options.has_key?(:confirm)
16
+ @options[:if] ||= :destroyable? if @name.to_s == "destroy"
17
+ @options[:if] ||= :editable? if @name.to_s == "edit"
18
+ @options[:confirm] = :are_you_sure if @options[:confirm].is_a?(TrueClass)
19
+ link_options = ""
20
+ if @options[:confirm]
21
+ link_options << ", 'data-confirm' => #{(@options[:confirm]).inspect}.t(scope: 'labels')"
22
+ end
23
+ if @options['data-method'] or @options[:method]
24
+ link_options << ", :method => h('#{(@options['data-method']||@options[:method])}')"
25
+ end
26
+ action = @name
27
+ format = @options[:format] ? ", :format => '#{@options[:format]}'" : ""
28
+ if @options[:remote]
29
+ raise StandardError, "Sure to use :remote ?"
30
+ # remote_options = @options.dup
31
+ # remote_options['data-confirm'] = "#{@options[:confirm].inspect}.tl".c unless @options[:confirm].nil?
32
+ # remote_options.delete :remote
33
+ # remote_options.delete :image
34
+ # remote_options = remote_options.inspect.to_s
35
+ # remote_options = remote_options[1..-2]
36
+ # code = "link_to_remote(#{image}"
37
+ # code += ", {url: {action: "+@name.to_s+", id: "+record+".id"+format+"}"
38
+ # code += ", "+remote_options+"}"
39
+ # code += ", {title: #{action.inspect}.tl}"
40
+ # code += ")"
41
+ elsif @options[:actions]
42
+ unless @options[:actions].is_a? Hash
43
+ raise StandardError, "options[:actions] have to be a Hash."
44
+ end
45
+ cases = []
46
+ for expected, url in @options[:actions]
47
+ cases << record+"."+@name.to_s+" == " + expected.inspect + "\nlink_to(content_tag(:i) + h(#{url[:action].inspect}.t(scope: 'labels'))"+
48
+ ", {"+(url[:controller] ? 'controller: :'+url[:controller].to_s+', ' : '')+"action: '"+url[:action].to_s+"', id: "+record+".id"+format+"}"+
49
+ ", {:class => '#{@name}'"+link_options+"}"+
50
+ ")\n"
51
+ end
52
+
53
+ code = "if "+cases.join("elsif ")+"end"
54
+ else
55
+ url = @options[:url] ||= {}
56
+ url[:controller] ||= (@options[:controller] || "RECORD.class.name.tableize".c) # self.table.model.name.underscore.pluralize.to_s
57
+ url[:action] ||= @name.to_s
58
+ url[:id] ||= "RECORD.id".c
59
+ url.delete_if{|k, v| v.nil?}
60
+ url = "{" + url.collect{|k, v| "#{k}: " + urlify(v, record)}.join(", ")+format+"}"
61
+ code = "{class: '#{@name}'"+link_options+"}"
62
+ code = "link_to(content_tag(:i) + h('#{action}'.t(scope: 'labels')), "+url+", "+code+")"
63
+ end
64
+ if @options[:if]
65
+ code = "if " + recordify!(@options[:if], record) + "\n" + code.dig + "end"
66
+ end
67
+ if @options[:unless]
68
+ code = "unless " + recordify!(@options[:unless], record) + "\n" + code.dig + "end"
69
+ end
70
+ code.c
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,80 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class AssociationColumn < DataColumn
6
+
7
+ attr_reader :label_method, :reflection
8
+
9
+ def initialize(table, name, options = {})
10
+ super(table, name, options)
11
+ unless @options[:through]
12
+ raise ArgumentError, "Option :through must be given"
13
+ end
14
+ reflection_name = @options.delete(:through).to_sym
15
+ if @reflection = @table.model.reflect_on_association(reflection_name)
16
+ if @reflection.macro == :belongs_to
17
+ # Do some stuff
18
+ elsif @reflection.macro == :has_one
19
+ # Do some stuff
20
+ else
21
+ raise ArgumentError, "Only belongs_to are usable. Can't handle: #{reflection.macro} :#{reflection.name}."
22
+ end
23
+ else
24
+ raise UnknownReflection, "Reflection #{reflection_name} cannot be found for #{table.model.name}."
25
+ end
26
+ columns_def = @reflection.class_name.constantize.columns_hash.keys.map(&:to_sym)
27
+ unless @label_method = @options.delete(:label_method)
28
+ columns = columns_def + @reflection.class_name.constantize.instance_methods.map(&:to_sym)
29
+ unless @label_method = LABELS_COLUMNS.detect{|m| columns.include?(m)}
30
+ raise ArgumentError, ":label_method option must be given for association #{name}. (#{columns.inspect})"
31
+ end
32
+ end
33
+ unless @sort_column = @options.delete(:sort)
34
+ if columns_def.include?(@label_method)
35
+ @sort_column = @label_method
36
+ else
37
+ unless @sort_column = LABELS_COLUMNS.detect{|m| columns_def.include?(m)}
38
+ @sort_column = :id
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ # Code for rows
46
+ def datum_code(record = 'record_of_the_death', child = false)
47
+ code = ""
48
+ if child
49
+ code = "nil"
50
+ # if @options[:children].is_a?(FalseClass)
51
+ # code = "nil"
52
+ # else
53
+ # code = "#{record}.#{table.options[:children]}.#{@reflection.name}.#{@options[:children] || @label_method}"
54
+ # end
55
+ else
56
+ code = "(#{record}.#{@reflection.name} ? #{record}.#{@reflection.name}.#{@label_method} : nil)"
57
+ end
58
+ return code.c
59
+ end
60
+
61
+ def class_name
62
+ return @reflection.class_name
63
+ end
64
+
65
+ def record_expr(record = 'record_of_the_death')
66
+ return "#{record}.#{@reflection.name}"
67
+ end
68
+
69
+ def sort_expression
70
+ if table.reflections.select{|r| r.table_name == @reflection.table_name}.size > 1
71
+ "#{@reflection.name.to_s.pluralize}_#{@reflection.class_name.constantize.table_name}.#{@sort_column}"
72
+ else
73
+ "#{@reflection.class_name.constantize.table_name}.#{@sort_column}"
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,58 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class AttributeColumn < DataColumn
6
+
7
+ attr_reader :column, :label_method, :sort_column
8
+
9
+ def initialize(table, name, options = {})
10
+ super(table, name, options)
11
+ @label_method = (options[:label_method] || @name).to_sym
12
+ unless @sort_column = options[:sort]
13
+ if @table.model.columns_hash[@label_method]
14
+ @sort_column = @label_method
15
+ elsif @table.model.columns_hash[@name]
16
+ @sort_column = @name
17
+ else
18
+ @sort_column = :id
19
+ end
20
+ end
21
+ @column = @table.model.columns_hash[@label_method.to_s]
22
+ end
23
+
24
+ # Code for rows
25
+ def datum_code(record = 'record_of_the_death', child = false)
26
+ code = ""
27
+ if child
28
+ if @options[:children].is_a?(FalseClass)
29
+ code = "nil"
30
+ else
31
+ code = "#{record}.#{table.options[:children]}.#{@options[:children] || @label_method}"
32
+ end
33
+ else
34
+ code = "#{record}.#{@label_method}"
35
+ end
36
+ return code.c
37
+ end
38
+
39
+ # Returns the class name of the used model
40
+ def class_name
41
+ return self.table.model.name
42
+ end
43
+
44
+ def enumerize?
45
+ self.table.model.send(@label_method).send(:values)
46
+ return true
47
+ rescue
48
+ return false
49
+ end
50
+
51
+ def sort_expression
52
+ "#{@table.model.table_name}.#{@sort_column}"
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class CheckBoxColumn < FieldColumn
6
+ attr_reader :form_value
7
+
8
+ def initialize(table, name, options = {})
9
+ super(table, name, options)
10
+ @form_value = options.delete(:form_value)
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class DataColumn < AbstractColumn
6
+
7
+ LABELS_COLUMNS = [:full_name, :label, :name, :number, :coordinate]
8
+
9
+ def header_code
10
+ if @options[:label]
11
+ "#{@options[:label].to_s.strip.inspect}.t(scope: 'labels')".c
12
+ else
13
+ "#{@table.model.name}.human_attribute_name(#{@name.inspect})".c
14
+ end
15
+ end
16
+
17
+ # Code for exportation
18
+ def exporting_datum_code(record='record_of_the_death', noview=false)
19
+ datum = self.datum_code(record)
20
+ if self.datatype == :boolean
21
+ datum = "(#{datum} ? ::I18n.translate('list.export.true_value') : ::I18n.translate('list.export.false_value'))"
22
+ elsif self.datatype == :date
23
+ datum = "(#{datum}.nil? ? '' : #{datum}.l)"
24
+ elsif self.datatype == :decimal and not noview
25
+ currency = nil
26
+ if currency = self.options[:currency]
27
+ currency = currency[:body] if currency.is_a?(Hash)
28
+ currency = :currency if currency.is_a?(TrueClass)
29
+ currency = "#{record}.#{currency}".c if currency.is_a?(Symbol)
30
+ end
31
+ datum = "(#{datum}.nil? ? '' : #{datum}.l(#{'currency: ' + currency.inspect if currency}))"
32
+ elsif @name.to_s.match(/(^|\_)currency$/) and self.datatype == :string
33
+ datum = "(Nomen::Currencies[#{datum}] ? Nomen::Currencies[#{datum}].human_name : '')"
34
+ elsif @name.to_s.match(/(^|\_)country$/) and self.datatype == :string
35
+ datum = "(Nomen::Countries[#{datum}] ? Nomen::Countries[#{datum}].human_name : '')"
36
+ elsif @name.to_s.match(/(^|\_)language$/) and self.datatype == :string
37
+ datum = "(Nomen::Languages[#{datum}] ? Nomen::Languages[#{datum}].human_name : '')"
38
+ elsif self.enumerize?
39
+ datum = "(#{datum}.nil? ? '' : #{datum}.text)"
40
+ end
41
+ return datum
42
+ end
43
+
44
+ # Returns the data type of the column if the column is in the database
45
+ def datatype
46
+ @options[:datatype] || (@column ? @column.type : nil)
47
+ end
48
+
49
+
50
+ def enumerize?
51
+ return false
52
+ end
53
+
54
+ def numeric?
55
+ [:decimal, :integer, :float, :numeric].include? self.datatype
56
+ end
57
+
58
+ # Returns the size/length of the column if the column is in the database
59
+ def limit
60
+ @column[:limit] if @column
61
+ end
62
+
63
+ # Defines if column is exportable
64
+ def exportable?
65
+ true
66
+ end
67
+
68
+ # Check if a column is sortable
69
+ def sortable?
70
+ return true
71
+ # not self.action? and
72
+ not self.options[:through] and not @column.nil?
73
+ end
74
+
75
+ # Generate code in order to get the (foreign) record of the column
76
+ def record_expr(record = 'record_of_the_death')
77
+ return record
78
+ end
79
+
80
+ def sort_expression
81
+ raise NotImplementedError, "sort_expression must be implemented"
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class EmptyColumn < AbstractColumn
6
+ end
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,20 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class FieldColumn < AbstractColumn
6
+ attr_reader :form_name
7
+
8
+ def initialize(table, name, options = {})
9
+ super(table, name, options)
10
+ @form_name = options.delete(:form_name)
11
+ end
12
+
13
+ def header_code
14
+ "#{@table.model.name}.human_attribute_name('#{@name}')"
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class StatusColumn < AttributeColumn
6
+ end
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,159 @@
1
+ module ActiveList
2
+
3
+ module Definition
4
+
5
+ class Table
6
+ attr_reader :name, :model, :options, :id, :columns, :parameters
7
+
8
+ def initialize(name, model = nil, options = {})
9
+ @name = name
10
+ @model = model || name.to_s.classify.constantize
11
+ @options = options
12
+ @paginate = !(@options[:pagination]==:none || @options[:paginate].is_a?(FalseClass))
13
+ @options[:renderer] ||= :simple_renderer
14
+ @options[:per_page] = 20 if @options[:per_page].to_i <= 0
15
+ @options[:page] = 1 if @options[:page].to_i <= 0
16
+ @columns = []
17
+ @id = ActiveList.new_uid
18
+ end
19
+
20
+ def new_column_id
21
+ @current_column_id ||= 0
22
+ id = @current_column_id.to_s(36).to_sym
23
+ @current_column_id += 1
24
+ return id
25
+ end
26
+
27
+ def model_columns
28
+ @model.columns_hash.values
29
+ end
30
+
31
+ def sortable_columns
32
+ @columns.select{|c| c.sortable?}
33
+ end
34
+
35
+ def exportable_columns
36
+ @columns.select{|c| c.exportable?}
37
+ end
38
+
39
+ def children
40
+ @columns.map(&:child)
41
+ end
42
+
43
+ def paginate?
44
+ @paginate
45
+ end
46
+
47
+ # Retrieves all columns in database
48
+ def table_columns
49
+ cols = self.model_columns.map(&:name)
50
+ @columns.select{|c| c.is_a? DataColumn and cols.include? c.name.to_s}
51
+ end
52
+
53
+ def data_columns
54
+ @columns.select{|c| c.is_a? DataColumn}
55
+ end
56
+
57
+ def hidden_columns
58
+ self.data_columns.select(&:hidden?)
59
+ end
60
+
61
+ # Compute includes Hash
62
+ def reflections
63
+ hash = []
64
+ for column in self.columns
65
+ if column.respond_to?(:reflection)
66
+ unless hash.detect{|r| r.name == column.reflection.name }
67
+ hash << column.reflection
68
+ end
69
+ end
70
+ end
71
+ return hash
72
+ end
73
+
74
+
75
+ # Add a new method in Table which permit to define text_field columns
76
+ def text_field(name, options = {})
77
+ add :text_field, name, options
78
+ end
79
+
80
+ # Add a new method in Table which permit to define check_box columns
81
+ def check_box(name, options = {})
82
+ add :check_box, name, options
83
+ end
84
+
85
+ # Add a new method in Table which permit to define action columns
86
+ def action(name, options = {})
87
+ add :action, name, options
88
+ end
89
+
90
+ # # Add a new method in Table which permit to define data columns
91
+ # def attribute(name, options = {})
92
+ # add :attribute, name, options
93
+ # end
94
+
95
+ # # Add a column referencing an association
96
+ # def association(name, options = {})
97
+ # options[:through] ||= name
98
+ # add :association, name, options
99
+ # end
100
+
101
+ # Add a new method in Table which permit to define data columns
102
+ def column(name, options = {})
103
+ if @model.reflect_on_association(name)
104
+ options[:through] ||= name
105
+ add :association, name, options
106
+ elsif @model.reflect_on_association(options[:through])
107
+ options[:label_method] ||= name
108
+ add :association, name, options
109
+ else
110
+ add :attribute, name, options
111
+ end
112
+ end
113
+
114
+ def status(*args)
115
+ options = args.extract_options!
116
+ name = args.shift || :status
117
+ add :status, name, options
118
+ end
119
+
120
+
121
+ def load_default_columns
122
+ for column in self.model_columns
123
+ reflections = @model.reflections.values.select{|r| r.macro == :belongs_to and r.foreign_key.to_s == column.name.to_s}
124
+ if reflections.size == 1
125
+ reflection = reflections.first
126
+ columns = reflection.class_name.constantize.columns.collect{ |c| c.name.to_s }
127
+ self.column([:label, :name, :code, :number].detect{ |l| columns.include?(l.to_s) }, :through => reflection.name, :url => true)
128
+ else
129
+ self.column(column.name)
130
+ end
131
+ end
132
+ return true
133
+ end
134
+
135
+ private
136
+
137
+ # Checks and add column
138
+ def add(type, name, options = {})
139
+ klass = "ActiveList::Definition::#{type.to_s.camelcase}Column".constantize rescue nil
140
+ if klass and klass < AbstractColumn
141
+ unless name.is_a?(Symbol)
142
+ raise ArgumentError, "Name of a column must be a Symbol (got #{name.inspect})."
143
+ end
144
+ if @columns.detect{|c| c.name == name}
145
+ raise ArgumentError, "Column name must be unique. #{name.inspect} is already used in #{self.name}"
146
+ end
147
+ @columns << klass.new(self, name, options)
148
+ else
149
+ raise ArgumentError, "Invalid column type: #{type.inspect}"
150
+ end
151
+ end
152
+
153
+
154
+ end
155
+
156
+
157
+ end
158
+
159
+ end