datagrid 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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?