datagrid 1.1.2 → 1.2.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +20 -0
  3. data/Readme.markdown +2 -0
  4. data/VERSION +1 -1
  5. data/app/views/datagrid/_head.html.erb +1 -1
  6. data/datagrid.gemspec +9 -3
  7. data/lib/datagrid.rb +0 -4
  8. data/lib/datagrid/active_model.rb +2 -1
  9. data/lib/datagrid/column_names_attribute.rb +3 -6
  10. data/lib/datagrid/columns.rb +115 -27
  11. data/lib/datagrid/drivers.rb +1 -1
  12. data/lib/datagrid/drivers/abstract_driver.rb +1 -1
  13. data/lib/datagrid/drivers/active_record.rb +1 -1
  14. data/lib/datagrid/drivers/array.rb +1 -1
  15. data/lib/datagrid/drivers/mongo_mapper.rb +1 -1
  16. data/lib/datagrid/drivers/mongoid.rb +1 -1
  17. data/lib/datagrid/form_builder.rb +15 -1
  18. data/lib/datagrid/helper.rb +45 -11
  19. data/lib/datagrid/renderer.rb +27 -6
  20. data/spec/datagrid/column_names_attribute_spec.rb +6 -0
  21. data/spec/datagrid/columns_spec.rb +103 -0
  22. data/spec/datagrid/drivers/mongo_mapper_spec.rb +1 -1
  23. data/spec/datagrid/drivers/mongoid_spec.rb +1 -1
  24. data/spec/datagrid/filters/date_filter_spec.rb +1 -1
  25. data/spec/datagrid/filters/date_time_filter_spec.rb +2 -2
  26. data/spec/datagrid/form_builder_spec.rb +28 -3
  27. data/spec/datagrid/helper_spec.rb +31 -4
  28. data/spec/spec_helper.rb +33 -2
  29. data/spec/support/matchers.rb +8 -23
  30. data/spec/support/mongo_mapper.rb +0 -4
  31. data/spec/support/mongoid.rb +0 -9
  32. data/spec/support/test_partials/client/datagrid/_form.html.erb +13 -0
  33. data/spec/support/test_partials/client/datagrid/_head.html.erb +9 -0
  34. data/spec/support/test_partials/client/datagrid/_order_for.html.erb +11 -0
  35. data/spec/support/test_partials/client/datagrid/_row.html.erb +6 -0
  36. data/spec/support/test_partials/client/datagrid/_table.html.erb +19 -0
  37. metadata +34 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 44f9ec4967241697a3299e94ea4c112eee7976a0
4
- data.tar.gz: 704336e23cb2865df032a9842a0c74797a43b19b
3
+ metadata.gz: 87a528983e7fd2ef73cf521c573fec464b5461cb
4
+ data.tar.gz: f74b44092e5cb1b1c5c076514c655c6874729f45
5
5
  SHA512:
6
- metadata.gz: ef2563a325877ffa13f721b5903e5381e064804a35d007e15d5ad279691504886e157c956a56698594351232782a9b9be45afb52038eacfad59f9e3553e31307
7
- data.tar.gz: f30f96c8b933c2cc71636f0183615a47c6fe25a0658ea6c4cfd0a6ca738babaf4a1606be3b32071bfc93a505f4d58975327231759f6e70dba57e16830781bfd2
6
+ metadata.gz: 5a60e18d5454ad9dabc58d4c367b5b93b1d589d6c4a5dc6aa8d2a7836b4046c587a21fdd694c1553f5746fb4c6b76851fb95a38d8062a6a1cb993e6f06081ff0
7
+ data.tar.gz: 09c2cc3b93a3387d1b36eb09bf42c226eeab2bb363ae0ea7db00280d38136b330f1c39bca03441b3969519f4526f413e86dfa8382f9c1b358e28138002b414a5
data/.travis.yml ADDED
@@ -0,0 +1,20 @@
1
+ language: ruby
2
+ #bundler_args: --without development
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.1
7
+ #- jruby
8
+ #- jruby-head
9
+ #env: JRUBY_OPTS="--server -J-Xms512m -J-Xmx1024m"
10
+ #matrix:
11
+ #allow_failures:
12
+ #- rvm: jruby-head
13
+ #- gemfile: gemfiles/rails41.gemfile
14
+ notifications:
15
+ email: false
16
+ services:
17
+ - mongodb
18
+ gemfile:
19
+ - Gemfile
20
+ #- gemfiles/rails41.gemfile
data/Readme.markdown CHANGED
@@ -1,5 +1,7 @@
1
1
  # Datagrid
2
2
 
3
+ [![Build Status](https://travis-ci.org/bogdan/datagrid.svg?branch=master)](https://travis-ci.org/bogdan/datagrid)
4
+
3
5
  Ruby library that helps you to build and represent table-like data with:
4
6
 
5
7
  * Customizable filtering
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.2
1
+ 1.2.0
@@ -2,7 +2,7 @@
2
2
  <% grid.html_columns(*options[:columns]).each do |column| %>
3
3
  <th class="<%= datagrid_column_classes(grid, column) %>">
4
4
  <%= column.header %>
5
- <%= datagrid_order_for(grid, column) if column.order && options[:order]%>
5
+ <%= datagrid_order_for(grid, column, options) if column.order && options[:order]%>
6
6
  </th>
7
7
  <% end %>
8
8
  </tr>
data/datagrid.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: datagrid 1.1.2 ruby lib
5
+ # stub: datagrid 1.2.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "datagrid"
9
- s.version = "1.1.2"
9
+ s.version = "1.2.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Bogdan Gusiev"]
14
- s.date = "2014-03-17"
14
+ s.date = "2014-05-10"
15
15
  s.description = "This allows you to easily build datagrid aka data tables with sortable columns and filters"
16
16
  s.email = "agresso@gmail.com"
17
17
  s.extra_rdoc_files = [
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.files = [
21
21
  ".document",
22
22
  ".rspec",
23
+ ".travis.yml",
23
24
  "Gemfile",
24
25
  "LICENSE.txt",
25
26
  "Rakefile",
@@ -105,6 +106,11 @@ Gem::Specification.new do |s|
105
106
  "spec/support/mongoid.rb",
106
107
  "spec/support/simple_report.rb",
107
108
  "spec/support/test_partials/_actions.html.erb",
109
+ "spec/support/test_partials/client/datagrid/_form.html.erb",
110
+ "spec/support/test_partials/client/datagrid/_head.html.erb",
111
+ "spec/support/test_partials/client/datagrid/_order_for.html.erb",
112
+ "spec/support/test_partials/client/datagrid/_row.html.erb",
113
+ "spec/support/test_partials/client/datagrid/_table.html.erb",
108
114
  "templates/controller.rb.erb",
109
115
  "templates/grid.rb.erb",
110
116
  "templates/index.html.erb"
data/lib/datagrid.rb CHANGED
@@ -24,7 +24,6 @@ module Datagrid
24
24
  autoload :Engine
25
25
 
26
26
  def self.included(base)
27
- base.extend ClassMethods
28
27
  base.class_eval do
29
28
 
30
29
  include ::Datagrid::Core
@@ -37,9 +36,6 @@ module Datagrid
37
36
  end
38
37
  end # self.included
39
38
 
40
- module ClassMethods
41
- end # ClassMethods
42
-
43
39
  class ConfigurationError < StandardError; end
44
40
  class ArgumentError < ::ArgumentError; end
45
41
 
@@ -2,7 +2,8 @@
2
2
  module Datagrid
3
3
 
4
4
  # Required to be ActiveModel compatible
5
- module ActiveModel
5
+ # @private
6
+ module ActiveModel #:nodoc:
6
7
 
7
8
  def self.included(base)
8
9
  base.extend ClassMethods
@@ -3,9 +3,6 @@ module Datagrid
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- class_attribute :columns_array
7
- self.columns_array = []
8
-
9
6
  datagrid_attribute :column_names do |names|
10
7
  names = Array(names).reject(&:blank?)
11
8
  if names.reject(&:blank?).blank?
@@ -48,12 +45,12 @@ module Datagrid
48
45
  # Returns a list of columns with <tt>:mandatory => true</tt> option
49
46
  # If no mandatory columns specified than all of them considered mandatory
50
47
  def mandatory_columns
51
- self.class.columns.select(&:mandatory?)
48
+ columns_array.select(&:mandatory?)
52
49
  end
53
50
 
54
51
  # Returns a list of columns without <tt>:mandatory => true</tt> option
55
52
  def optional_columns
56
- self.class.columns - mandatory_columns
53
+ columns_array - mandatory_columns
57
54
  end
58
55
 
59
56
  protected
@@ -77,7 +74,7 @@ module Datagrid
77
74
  end
78
75
 
79
76
  def columns_visibility_enabled?
80
- self.class.columns.any? do |column|
77
+ columns_array.any? do |column|
81
78
  column.options.key?(:mandatory)
82
79
  end
83
80
  end
@@ -12,11 +12,16 @@ module Datagrid
12
12
 
13
13
  include Datagrid::Core
14
14
 
15
- class_attribute :default_column_options
15
+ class_attribute :default_column_options, :instance_writer => false
16
16
  self.default_column_options = {}
17
17
 
18
18
  class_attribute :batch_size
19
19
 
20
+ class_attribute :columns_array
21
+ self.columns_array = []
22
+
23
+ class_attribute :dynamic_block, :instance_writer => false
24
+
20
25
  end
21
26
  base.send :include, InstanceMethods
22
27
  end # self.included
@@ -72,18 +77,13 @@ module Datagrid
72
77
  # All column definistion are returned by default
73
78
  # You can limit the output with only columns you need like:
74
79
  #
75
- # grid.columns(:id, :name)
80
+ # GridClass.columns(:id, :name)
76
81
  #
77
82
  # Supported options:
78
83
  #
79
84
  # * :data - if true returns only non-html columns. Default: false.
80
85
  def columns(*args)
81
- options = args.extract_options!
82
- args.compact!
83
- args.map!(&:to_sym)
84
- columns_array.select do |column|
85
- (!options[:data] || column.data?) && (!options[:html] || column.html?) && (column.mandatory? || args.empty? || args.include?(column.name))
86
- end
86
+ filter_columns(columns_array, *args)
87
87
  end
88
88
 
89
89
  # Defines new datagrid column
@@ -116,25 +116,12 @@ module Datagrid
116
116
  #
117
117
  # See: https://github.com/bogdan/datagrid/wiki/Columns for examples
118
118
  def column(name, options_or_query = {}, options = {}, &block)
119
- if options_or_query.is_a?(String)
120
- query = options_or_query
121
- else
122
- options = options_or_query
123
- end
124
- check_scope_defined!("Scope should be defined before columns")
125
- block ||= lambda do |model|
126
- model.send(name)
127
- end
128
- position = Datagrid::Utils.extract_position_from_options(columns_array, options)
129
- column = Datagrid::Columns::Column.new(self, name, query, default_column_options.merge(options), &block)
130
- columns_array.insert(position, column)
119
+ define_column(columns_array, name, options_or_query, options, &block)
131
120
  end
132
121
 
133
122
  # Returns column definition with given name
134
123
  def column_by_name(name)
135
- self.columns.find do |col|
136
- col.name.to_sym == name.to_sym
137
- end
124
+ find_column_by_name(columns_array, name)
138
125
  end
139
126
 
140
127
  # Returns an array of all defined column names
@@ -146,6 +133,14 @@ module Datagrid
146
133
  Datagrid::Columns::Column::ResponseFormat.new(&block)
147
134
  end
148
135
 
136
+ # Formats column value for HTML.
137
+ # Helps to distinguish formatting as plain data and HTML
138
+ #
139
+ # column(:name) do |model|
140
+ # format(model.name) do |value|
141
+ # content_tag(:strong, value)
142
+ # end
143
+ # end
149
144
  def format(value, &block)
150
145
  if block_given?
151
146
  respond_to do |f|
@@ -161,11 +156,72 @@ module Datagrid
161
156
  end
162
157
  end
163
158
 
159
+ # Allows dynamic columns definition, that could not be defined at class level
160
+ #
161
+ # class MerchantsGrid
162
+ #
163
+ # scope { Merchant }
164
+ #
165
+ # column(:name)
166
+ #
167
+ # dynamic do
168
+ # PurchaseCategory.all.each do |category|
169
+ # column(:"#{category.name.underscore}_sales") do |merchant|
170
+ # merchant.purchases.where(:category_id => category.id).count
171
+ # end
172
+ # end
173
+ # end
174
+ # end
175
+ #
176
+ # grid = MerchantsGrid.new
177
+ # grid.data # => [
178
+ # # [ "Name", "Swimwear Sales", "Sportswear Sales", ... ]
179
+ # # [ "Reebok", 2083382, 8382283, ... ]
180
+ # # [ "Nike", 8372283, 18734783, ... ]
181
+ # # ]
182
+ def dynamic(&block)
183
+ previous_block = dynamic_block
184
+ self.dynamic_block = proc {
185
+ instance_eval(&previous_block) if previous_block
186
+ instance_eval(&block)
187
+ }
188
+ end
189
+
164
190
  def inherited(child_class) #:nodoc:
165
191
  super(child_class)
166
192
  child_class.columns_array = self.columns_array.clone
167
193
  end
168
194
 
195
+ def filter_columns(columns, *args) #:nodoc:
196
+ options = args.extract_options!
197
+ args.compact!
198
+ args.map!(&:to_sym)
199
+ columns.select do |column|
200
+ (!options[:data] || column.data?) && (!options[:html] || column.html?) && (column.mandatory? || args.empty? || args.include?(column.name))
201
+ end
202
+ end
203
+
204
+ def define_column(columns, name, options_or_query = {}, options = {}, &block) #:nodoc:
205
+ if options_or_query.is_a?(String)
206
+ query = options_or_query
207
+ else
208
+ options = options_or_query
209
+ end
210
+ check_scope_defined!("Scope should be defined before columns")
211
+ block ||= lambda do |model|
212
+ model.send(name)
213
+ end
214
+ position = Datagrid::Utils.extract_position_from_options(columns, options)
215
+ column = Datagrid::Columns::Column.new(self, name, query, default_column_options.merge(options), &block)
216
+ columns.insert(position, column)
217
+ end
218
+
219
+ def find_column_by_name(columns,name) #:nodoc:
220
+ columns.find do |col|
221
+ col.name.to_sym == name.to_sym
222
+ end
223
+ end
224
+
169
225
  end # ClassMethods
170
226
 
171
227
  module InstanceMethods
@@ -277,7 +333,7 @@ module Datagrid
277
333
  # grid.columns # => id and name columns
278
334
  # grid.columns(:id, :category) # => id and category column
279
335
  def columns(*args)
280
- self.class.columns(*args).select {|column| column.enabled?(self)}
336
+ self.class.filter_columns(columns_array, *args).select {|column| column.enabled?(self)}
281
337
  end
282
338
 
283
339
  # Returns all columns that can be represented in plain data(non-html) way
@@ -298,10 +354,9 @@ module Datagrid
298
354
 
299
355
  # Finds a column definition by name
300
356
  def column_by_name(name)
301
- self.class.column_by_name(name)
357
+ self.class.find_column_by_name(columns_array, name)
302
358
  end
303
359
 
304
-
305
360
  # Gives ability to have a different formatting for CSV and HTML column value.
306
361
  #
307
362
  # Example:
@@ -347,6 +402,40 @@ module Datagrid
347
402
  ::Datagrid::Columns::DataRow.new(self, asset)
348
403
  end
349
404
 
405
+ # Defines a column at instance level
406
+ #
407
+ # See Datagrid::Columns::ClassMethods#column for more info
408
+ def column(name, options_or_query = {}, options = {}, &block) #:nodoc:
409
+ self.class.define_column(columns_array, name, options_or_query, options, &block)
410
+ end
411
+
412
+ def initialize(*) #:nodoc:
413
+ self.columns_array = self.class.columns_array.clone
414
+ instance_eval(&dynamic_block) if dynamic_block
415
+ super
416
+ end
417
+
418
+ # Returns all columns available for current grid configuration
419
+ #
420
+ # class MyGrid
421
+ # filter(:search)
422
+ # column(:id)
423
+ # column(:name, :mandatory => true)
424
+ # column(:search_match, :if => proc {|grid| grid.search.present? }
425
+ # end
426
+ #
427
+ # grid = MyGrid.new
428
+ # grid.columns # => [ <#Column:name> ]
429
+ # grid.available_columns # => [ <#Column:id>, <#Column:name> ]
430
+ # grid.search = "keyword"
431
+ # grid.available_columns # => [ <#Column:id>, <#Column:name>, <#Column:search_match> ]
432
+ #
433
+ def available_columns
434
+ columns_array.select do |column|
435
+ column.enabled?(self)
436
+ end
437
+ end
438
+
350
439
  protected
351
440
 
352
441
  def map_with_batches(&block)
@@ -365,7 +454,6 @@ module Datagrid
365
454
  end
366
455
  end
367
456
 
368
-
369
457
  def csv_class
370
458
  if RUBY_VERSION >= "1.9"
371
459
  require 'csv'
@@ -6,6 +6,6 @@ require "datagrid/drivers/mongo_mapper"
6
6
 
7
7
 
8
8
  module Datagrid
9
- module Drivers
9
+ module Drivers # :nodoc:
10
10
  end
11
11
  end
@@ -1,6 +1,6 @@
1
1
  module Datagrid
2
2
  module Drivers
3
- class AbstractDriver
3
+ class AbstractDriver #:nodoc:
4
4
 
5
5
  TIMESTAMP_CLASSES = [DateTime, Time, ActiveSupport::TimeWithZone]
6
6
 
@@ -1,6 +1,6 @@
1
1
  module Datagrid
2
2
  module Drivers
3
- class ActiveRecord < AbstractDriver
3
+ class ActiveRecord < AbstractDriver #:nodoc:
4
4
 
5
5
  def self.match?(scope)
6
6
  return false unless defined?(::ActiveRecord)
@@ -1,6 +1,6 @@
1
1
  module Datagrid
2
2
  module Drivers
3
- class Array < AbstractDriver
3
+ class Array < AbstractDriver #:nodoc:
4
4
 
5
5
  def self.match?(scope)
6
6
  !Datagrid::Drivers::ActiveRecord.match?(scope) && scope.is_a?(::Array)
@@ -1,6 +1,6 @@
1
1
  module Datagrid
2
2
  module Drivers
3
- class MongoMapper < AbstractDriver
3
+ class MongoMapper < AbstractDriver #:nodoc:
4
4
 
5
5
  def self.match?(scope)
6
6
  return false unless defined?(::MongoMapper)
@@ -1,6 +1,6 @@
1
1
  module Datagrid
2
2
  module Drivers
3
- class Mongoid < AbstractDriver
3
+ class Mongoid < AbstractDriver #:nodoc:
4
4
 
5
5
  def self.match?(scope)
6
6
  return false unless defined?(::Mongoid)
@@ -50,7 +50,10 @@ module Datagrid
50
50
  filter.select(object).map do |element|
51
51
  text, value = @template.send(:option_text_and_value, element)
52
52
  id = [object_name, filter.name, value].join('_').underscore
53
- input = check_box(filter.name, datagrid_extra_checkbox_options.reverse_merge(:id => id, :multiple => true), value.to_s, nil)
53
+ html_options = datagrid_extra_checkbox_options.reverse_merge(
54
+ :id => id, :multiple => true, :checked => enum_checkbox_checked?(filter, value)
55
+ )
56
+ input = check_box(filter.name, html_options, value.to_s, nil)
54
57
  label(filter.name, input + text, options.reverse_merge(:for => id))
55
58
  end.join("\n").html_safe
56
59
  else
@@ -61,6 +64,17 @@ module Datagrid
61
64
  end
62
65
  end
63
66
 
67
+ def enum_checkbox_checked?(filter, option_value)
68
+ current_value = object.send(filter.name)
69
+ if current_value.respond_to?(:include?)
70
+ # Typecast everything to string
71
+ # to remove difference between String and Symbol
72
+ current_value.map(&:to_s).include?(option_value.to_s)
73
+ else
74
+ current_value.to_s == option_value.to_s
75
+ end
76
+ end
77
+
64
78
  def datagrid_integer_filter(attribute_or_filter, options = {})
65
79
  filter = datagrid_get_filter(attribute_or_filter)
66
80
  if filter.multiple? && self.object[filter.name].blank?