tabulatr 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Changelog.textile +20 -0
- data/lib/initializers/mongoid.rb +11 -9
- data/lib/tabulatr/tabulatr.rb +28 -11
- data/lib/tabulatr/tabulatr/adapter.rb +55 -0
- data/lib/tabulatr/tabulatr/adapter/active_record.rb +72 -0
- data/lib/tabulatr/tabulatr/adapter/mongoid.rb +54 -0
- data/lib/tabulatr/tabulatr/data_cell.rb +1 -1
- data/lib/tabulatr/tabulatr/finder.rb +1 -49
- data/lib/tabulatr/tabulatr/finder/find_for_table.rb +58 -82
- data/lib/tabulatr/tabulatr/formattr.rb +6 -2
- data/lib/tabulatr/tabulatr/header_cell.rb +1 -0
- data/lib/tabulatr/tabulatr/settings.rb +4 -2
- data/lib/tabulatr/version.rb +1 -1
- data/spec/dummy_app/app/models/product.rb +1 -1
- data/spec/dummy_app/config/application.rb +2 -2
- data/spec/requests/tabulatrs_spec.rb +24 -39
- data/tabulatr.gemspec +1 -1
- metadata +12 -9
data/.gitignore
CHANGED
data/Changelog.textile
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
h1. Changelog for tabulatr
|
2
2
|
|
3
|
+
h2. 0.4.0
|
4
|
+
|
5
|
+
* Mongoid now really works.
|
6
|
+
* A lot of cleanup in the finder code (million thanks to <a href="https://github.com/plukevdh">plukevdh</a>)
|
7
|
+
* You can use <tt>table_for</tt> for 'normal' arrays that weren't found with <tt>find_for_table</tt>.
|
8
|
+
* Added a :name_mapping option to find_for_table to allow filtering by compund expressions, example:
|
9
|
+
|
10
|
+
<pre>
|
11
|
+
@customers = Customer.find_for_table(params,
|
12
|
+
name_mapping: {
|
13
|
+
name: '("addresses"."firstname" || \' \' || "addresses"."lastname")',
|
14
|
+
address: '("addresses"."street" || \' \' || "addresses"."zip_code" || \' \' || "addresses"."city")'
|
15
|
+
},
|
16
|
+
default_order: 'updated_at desc'
|
17
|
+
)
|
18
|
+
</pre>
|
19
|
+
|
20
|
+
* Added Mysql2Adapter to the ActiveRecord connection list (thanks to <a href="https://github.com/AaronLasseigne">AaronLasseigne</a>).
|
21
|
+
* Monkeypatch mongoid only if it is present. (thanks to <a href="https://github.com/rwz">rwz</a>)
|
22
|
+
|
3
23
|
h2. 0.3.0
|
4
24
|
|
5
25
|
* Converted into a Rails 3.1 engine and moved css and images to use the new asset pipeline. Works with 3.0.x -- 'opefully. Thanks to all that reported the problem.
|
data/lib/initializers/mongoid.rb
CHANGED
@@ -21,15 +21,17 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
module
|
29
|
-
module
|
30
|
-
|
31
|
-
|
24
|
+
# ensure mongoid is loaded *before* monkeypatching
|
25
|
+
begin; require 'mongoid'; rescue LoadError; end
|
26
|
+
|
27
|
+
if defined? ::Mongoid
|
28
|
+
module Mongoid
|
29
|
+
module Document
|
30
|
+
module ClassMethods
|
31
|
+
def find_for_table(params, opts={}, &block)
|
32
|
+
Tabulatr::Finder.find_for_table(self, params, opts, &block)
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
|
-
end
|
37
|
+
end
|
data/lib/tabulatr/tabulatr.rb
CHANGED
@@ -59,14 +59,30 @@ class Tabulatr
|
|
59
59
|
@val = []
|
60
60
|
@record = nil
|
61
61
|
@row_mode = false
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
if @records.respond_to? :__classinfo
|
63
|
+
@klaz, @classname, @id, @id_type = @records.__classinfo
|
64
|
+
@pagination = @records.__pagination
|
65
|
+
@filters = @records.__filters
|
66
|
+
@sorting = @records.__sorting
|
67
|
+
@checked = @records.__checked
|
68
|
+
@store_data = @records.__store_data
|
69
|
+
@stateful = @records.__stateful
|
70
|
+
@should_translate = @table_options[:translate]
|
71
|
+
else
|
72
|
+
@classname, @id, @id_type = nil
|
73
|
+
@klaz = @records.first.class
|
74
|
+
@pagination = { :page => 1, :pagesize => records.count, :count => records.count, :pages => 1,
|
75
|
+
:pagesizes => records.count, :total => records.count }
|
76
|
+
@table_options.merge!(
|
77
|
+
:paginate => false, # true to show paginator
|
78
|
+
:sortable => false, # true to allow sorting (can be specified for every sortable column)
|
79
|
+
:selectable => false, # true to render "select all", "select none" and the like
|
80
|
+
:info_text => nil,
|
81
|
+
:filter => false
|
82
|
+
)
|
83
|
+
@store_data = []
|
84
|
+
@should_translate = @table_options[:translate]
|
85
|
+
end
|
70
86
|
end
|
71
87
|
|
72
88
|
# the actual table definition method. It takes an Array of records, a hash of
|
@@ -116,7 +132,7 @@ class Tabulatr
|
|
116
132
|
when :hidden_submit then "IMPLEMENT ME!"
|
117
133
|
when :submit then make_tag(:input, :type => 'submit',
|
118
134
|
:class => @table_options[:submit_class],
|
119
|
-
:value => t(@table_options[:submit_label]))
|
135
|
+
:value => t(@table_options[:submit_label])) if @records.respond_to?(:__classinfo)
|
120
136
|
when :reset then make_tag(:input, :type => 'submit',
|
121
137
|
:class => @table_options[:reset_class],
|
122
138
|
:name => "#{@classname}#{TABLE_FORM_OPTIONS[:reset_state_postfix]}",
|
@@ -149,6 +165,7 @@ class Tabulatr
|
|
149
165
|
make_tag(:tbody) do
|
150
166
|
render_table_rows(&block)
|
151
167
|
end # </tbody>
|
168
|
+
content_for(@table_options[:footer_content]) if @table_options[:footer_content]
|
152
169
|
end # </table>
|
153
170
|
end
|
154
171
|
|
@@ -239,12 +256,12 @@ private
|
|
239
256
|
end
|
240
257
|
nil
|
241
258
|
end
|
242
|
-
|
259
|
+
|
243
260
|
def make_image_button(iname, options)
|
244
261
|
inactive = options.delete(:inactive)
|
245
262
|
psrc = @view.image_path File.join(@table_options[:image_path_prefix], iname)
|
246
263
|
if !inactive
|
247
|
-
make_tag(:input,
|
264
|
+
make_tag(:input,
|
248
265
|
options.merge(
|
249
266
|
:type => 'image',
|
250
267
|
:src => psrc
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Tabulatr::Adapter
|
2
|
+
def initialize(klaz)
|
3
|
+
@base = klaz
|
4
|
+
@relation = klaz
|
5
|
+
end
|
6
|
+
|
7
|
+
delegate :all, :dup, :count, :limit, to: :@relation
|
8
|
+
|
9
|
+
def to_sql
|
10
|
+
@relation.to_sql if @relation.respond_to? :to_sql
|
11
|
+
end
|
12
|
+
|
13
|
+
def class_to_param
|
14
|
+
@relation.to_s.downcase.gsub("/","_")
|
15
|
+
end
|
16
|
+
|
17
|
+
def preconditions_scope(opts)
|
18
|
+
opts[:precondition].present? ? @base.where(opts[:precondition]) : @base
|
19
|
+
end
|
20
|
+
|
21
|
+
def order(sortparam, default)
|
22
|
+
order_by, order_direction = sort_params(sortparam, default)
|
23
|
+
order_by ? { :by => order_by, :direction => order_direction } : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def sort_params(sortparam, default)
|
27
|
+
if sortparam
|
28
|
+
if sortparam[:_resort]
|
29
|
+
order_by = sortparam[:_resort].first.first
|
30
|
+
order_direction = sortparam[:_resort].first.last.first.first
|
31
|
+
else
|
32
|
+
order_by = sortparam.first.first
|
33
|
+
order_direction = sortparam.first.last.first.first
|
34
|
+
end
|
35
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\w]+$/.match order_direction
|
36
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\d\w]+$/.match order_by
|
37
|
+
else
|
38
|
+
if default
|
39
|
+
l = default.split(" ")
|
40
|
+
raise(":default_order parameter should be of the form 'id asc' or 'name desc'.") if l.length == 0 or l.length > 2
|
41
|
+
|
42
|
+
order_by = l[0]
|
43
|
+
order_direction = l[1] || 'asc'
|
44
|
+
else
|
45
|
+
order_by = order_direction = nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return order_by, order_direction
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Dir[File.join(File.dirname(__FILE__), "adapter", "*.rb")].each do |file|
|
54
|
+
require file
|
55
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Tabulatr::Adapter::ActiveRecordAdapter < Tabulatr::Adapter
|
2
|
+
|
3
|
+
def initialize(klaz)
|
4
|
+
set_like_statement unless Tabulatr::SQL_OPTIONS[:like]
|
5
|
+
|
6
|
+
super klaz
|
7
|
+
end
|
8
|
+
|
9
|
+
def primary_key
|
10
|
+
@relation.primary_key.to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
def key_type
|
14
|
+
@relation.columns_hash[primary_key.to_s].type
|
15
|
+
end
|
16
|
+
|
17
|
+
def selected_ids(opts)
|
18
|
+
preconditions_scope(opts).select(:id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def table_name
|
22
|
+
@relation.table_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def table_name_for_association(assoc)
|
26
|
+
@base.reflect_on_association(assoc).table_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def order_for_query(sortparam, default)
|
30
|
+
context = order(sortparam, default)
|
31
|
+
context.values.join(" ") if context
|
32
|
+
end
|
33
|
+
|
34
|
+
def includes(inc)
|
35
|
+
@relation.includes(inc)
|
36
|
+
end
|
37
|
+
|
38
|
+
def includes!(inc)
|
39
|
+
@relation = includes(includes)
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_conditions_from(n,v)
|
43
|
+
like ||= Tabulatr.sql_options[:like]
|
44
|
+
if v.is_a?(String)
|
45
|
+
@relation = @relation.where(n => v) unless v.blank?
|
46
|
+
elsif v.is_a?(Hash)
|
47
|
+
if v[:like].present?
|
48
|
+
@relation = @relation.where("#{n} #{like} ?", "%#{v[:like]}%")
|
49
|
+
else
|
50
|
+
@relation = @relation.where("#{n} >= ?", "#{v[:from]}") if v[:from].present?
|
51
|
+
@relation = @relation.where("#{n} <= ?", "#{v[:to]}") if v[:to].present?
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise "Wrong filter type: #{v.class}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def set_like_statement
|
60
|
+
case ActiveRecord::Base.connection.class.to_s
|
61
|
+
when "ActiveRecord::ConnectionAdapters::MysqlAdapter" then Tabulatr.sql_options(:like => 'LIKE')
|
62
|
+
when "ActiveRecord::ConnectionAdapters::Mysql2Adapter" then Tabulatr.sql_options(:like => 'LIKE')
|
63
|
+
when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter" then Tabulatr.sql_options(:like => 'ILIKE')
|
64
|
+
when "ActiveRecord::ConnectionAdapters::SQLiteAdapter" then Tabulatr.sql_options(:like => 'LIKE')
|
65
|
+
when "ActiveRecord::ConnectionAdapters::SQLite3Adapter" then Tabulatr.sql_options(:like => 'LIKE')
|
66
|
+
else
|
67
|
+
warn("Tabulatr Warning: Don't know which LIKE operator to use for the ConnectionAdapter '#{ActiveRecord::Base.connection.class}'.\n" +
|
68
|
+
"Please specify by `Tabulatr.sql_options(:like => '<likeoperator>')`")
|
69
|
+
Tabulatr.sql_options(:like => 'LIKE')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Tabulatr::Adapter::MongoidAdapter < Tabulatr::Adapter
|
2
|
+
def primary_key
|
3
|
+
:id
|
4
|
+
end
|
5
|
+
|
6
|
+
def key_type
|
7
|
+
:string
|
8
|
+
end
|
9
|
+
|
10
|
+
def selected_ids(opts)
|
11
|
+
preconditions_scope(opts).only(:id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def table_name
|
15
|
+
if Object.const_defined?("Mongoid") && @relation.is_a?(Mongoid::Criteria)
|
16
|
+
@relation.klass
|
17
|
+
else
|
18
|
+
@relation
|
19
|
+
end.to_s.tableize.gsub('/','_')
|
20
|
+
end
|
21
|
+
|
22
|
+
def table_name_for_association(assoc)
|
23
|
+
assoc.to_s.tableize
|
24
|
+
end
|
25
|
+
|
26
|
+
def order_for_query(sortparam, default)
|
27
|
+
context = order(sortparam, default)
|
28
|
+
context.values.map(&:to_s) if context
|
29
|
+
end
|
30
|
+
|
31
|
+
def includes(includes)
|
32
|
+
@relation # do nothing with includes
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_conditions_from(n,v)
|
36
|
+
if v.is_a?(String)
|
37
|
+
nn = n.split('.').last
|
38
|
+
@relation = @relation.where(nn => v) unless v.blank?
|
39
|
+
elsif v.is_a?(Hash)
|
40
|
+
if v[:like].present?
|
41
|
+
nn = n.split('.').last
|
42
|
+
@relation = @relation.where(nn => Regexp.new(v[:like]))
|
43
|
+
else
|
44
|
+
nn = n.split('.').last.to_sym
|
45
|
+
@relation = @relation.where(nn.gte => v[:from]) if v[:from].present?
|
46
|
+
@relation = @relation.where(nn.lte => v[:to]) if v[:to].present?
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise "Wrong filter type: #{v.class}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -84,7 +84,7 @@ class Tabulatr
|
|
84
84
|
if opts[:sort_by]
|
85
85
|
# TODO: SORTING specified by opts[:sort_by]
|
86
86
|
end
|
87
|
-
concat(if (ass.is_a?(Array)
|
87
|
+
concat(if (ass.is_a?(Array) || ass.respond_to?(:to_ary)) && opts[:map]
|
88
88
|
ass.map do |r|
|
89
89
|
val = h(r.send(opts[:method] || name))
|
90
90
|
if format.is_a?(Proc) then format.call(val)
|
@@ -34,7 +34,7 @@ module Tabulatr::Finder
|
|
34
34
|
elsif list.first.is_a?(Fixnum)
|
35
35
|
IdStuffer.stuff(list)
|
36
36
|
else
|
37
|
-
"GzB" + Base64.
|
37
|
+
"GzB" + Base64.encode64(
|
38
38
|
Zlib::Deflate.deflate(
|
39
39
|
list.join(Tabulatr.table_form_options[:checked_separator])))
|
40
40
|
end
|
@@ -65,52 +65,4 @@ module Tabulatr::Finder
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
private
|
69
|
-
|
70
|
-
def self.class_to_param(klaz)
|
71
|
-
klaz.to_s.downcase.gsub("/","_")
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.condition_from(rel, typ, n, v)
|
75
|
-
raise "SECURITY violation, field name is '#{n}'" unless /^[\d\w]+(\.[\d\w]+)?$/.match n
|
76
|
-
@like ||= Tabulatr.sql_options[:like]
|
77
|
-
if v.is_a?(String)
|
78
|
-
if v.present?
|
79
|
-
if typ == :ar
|
80
|
-
rel = rel.where(n => v)
|
81
|
-
elsif typ == :mongoid
|
82
|
-
nn = n.split('.').last
|
83
|
-
rel = rel.where(nn => v)
|
84
|
-
else raise "Unknown db type '#{typ}'"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
elsif v.is_a?(Hash)
|
88
|
-
if v[:like]
|
89
|
-
if v[:like].present?
|
90
|
-
if typ==:ar
|
91
|
-
rel = rel.where("#{n} #{@like} ?", "%#{v[:like]}%")
|
92
|
-
elsif typ==:mongoid
|
93
|
-
nn = n.split('.').last
|
94
|
-
rel = rel.where(nn => Regexp.new(v[:like]))
|
95
|
-
else
|
96
|
-
raise "Unknown db type '#{typ}'"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
else
|
100
|
-
if typ==:ar
|
101
|
-
rel = rel.where("#{n} >= ?", "#{v[:from]}") if v[:from].present?
|
102
|
-
rel = rel.where("#{n} <= ?", "#{v[:to]}") if v[:to].present?
|
103
|
-
elsif typ==:mongoid
|
104
|
-
nn = n.split('.').last.to_sym
|
105
|
-
rel = rel.where(nn.gte => v[:from]) if v[:from].present?
|
106
|
-
rel = rel.where(nn.lte => v[:to]) if v[:to].present?
|
107
|
-
else
|
108
|
-
raise "Unknown db type '#{typ}'"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
else
|
112
|
-
raise "Wrong filter type: #{v.class}"
|
113
|
-
end
|
114
|
-
rel
|
115
|
-
end
|
116
68
|
end
|
@@ -23,36 +23,22 @@
|
|
23
23
|
|
24
24
|
# These are extensions for use from ActionController instances
|
25
25
|
# In a seperate class call only for clearity
|
26
|
+
|
26
27
|
module Tabulatr::Finder
|
27
28
|
|
28
29
|
# -------------------------------------------------------------------
|
29
30
|
# Called if SomeActveRecordSubclass::find_for_table(params) is called
|
30
31
|
#
|
31
|
-
def self.find_for_table(klaz, params,
|
32
|
-
|
33
|
-
|
34
|
-
elsif klaz.include?(Mongoid::Document) then :mongoid
|
32
|
+
def self.find_for_table(klaz, params, options={}, &block)
|
33
|
+
adapter = if klaz.respond_to?(:descends_from_active_record?) then ::Tabulatr::Adapter::ActiveRecordAdapter.new(klaz)
|
34
|
+
elsif klaz.include?(Mongoid::Document) then ::Tabulatr::Adapter::MongoidAdapter.new(klaz)
|
35
35
|
else raise("Don't know how to deal with class '#{klaz}'")
|
36
36
|
end
|
37
|
-
|
38
|
-
# on the first run, get the correct like db-operator, can still be ovrrridden
|
39
|
-
unless typ != :ar || Tabulatr::SQL_OPTIONS[:like]
|
40
|
-
case ActiveRecord::Base.connection.class.to_s
|
41
|
-
when "ActiveRecord::ConnectionAdapters::MysqlAdapter" then Tabulatr.sql_options(:like => 'LIKE')
|
42
|
-
when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter" then Tabulatr.sql_options(:like => 'ILIKE')
|
43
|
-
when "ActiveRecord::ConnectionAdapters::SQLiteAdapter" then Tabulatr.sql_options(:like => 'LIKE')
|
44
|
-
when "ActiveRecord::ConnectionAdapters::SQLite3Adapter" then Tabulatr.sql_options(:like => 'LIKE')
|
45
|
-
else
|
46
|
-
warn("Tabulatr Warning: Don't know which LIKE operator to use for the ConnectionAdapter '#{ActiveRecord::Base.connection.class}'.\n" +
|
47
|
-
"Please specify by `Tabulatr.sql_options(:like => '<likeoperator>')`")
|
48
|
-
Tabulatr.sql_options(:like => 'LIKE')
|
49
|
-
end
|
50
|
-
end
|
51
37
|
|
52
|
-
form_options
|
53
|
-
opts
|
54
|
-
params
|
55
|
-
cname = class_to_param
|
38
|
+
form_options = Tabulatr.table_form_options
|
39
|
+
opts = Tabulatr.finder_options.merge(options)
|
40
|
+
params ||= {} # just to be sure
|
41
|
+
cname = adapter.class_to_param
|
56
42
|
pagination_name = "#{cname}#{form_options[:pagination_postfix]}"
|
57
43
|
sort_name = "#{cname}#{form_options[:sort_postfix]}"
|
58
44
|
filter_name = "#{cname}#{form_options[:filter_postfix]}"
|
@@ -62,23 +48,25 @@ module Tabulatr::Finder
|
|
62
48
|
# before we do anything else, we find whether there's something to do for batch actions
|
63
49
|
checked_param = ActiveSupport::HashWithIndifferentAccess.new({:checked_ids => '', :current_page => []}).
|
64
50
|
merge(params[check_name] || {})
|
65
|
-
|
66
|
-
|
51
|
+
|
52
|
+
id = adapter.primary_key
|
53
|
+
id_type = adapter.key_type
|
54
|
+
|
55
|
+
# checkboxes
|
67
56
|
checked_ids = uncompress_id_list(checked_param[:checked_ids])
|
68
57
|
new_ids = checked_param[:current_page]
|
69
58
|
new_ids.map!(&:to_i) if id_type==:integer
|
59
|
+
|
70
60
|
selected_ids = checked_ids + new_ids
|
71
61
|
batch_param = params[batch_name]
|
72
62
|
if batch_param.present? and block_given?
|
73
63
|
batch_param = batch_param.keys.first.to_sym if batch_param.is_a?(Hash)
|
74
64
|
yield(Invoker.new(batch_param, selected_ids))
|
75
65
|
end
|
76
|
-
|
66
|
+
|
77
67
|
# then, we obey any "select" buttons if pushed
|
78
|
-
precon = rel
|
79
|
-
precon = precon.where(opts[:precondition]) if opts[:precondition].present?
|
80
68
|
if checked_param[:select_all]
|
81
|
-
selected_ids =
|
69
|
+
selected_ids = adapter.selected_ids(opts).to_a.map { |r| r.send(id) }
|
82
70
|
elsif checked_param[:select_none]
|
83
71
|
selected_ids = []
|
84
72
|
elsif checked_param[:select_visible]
|
@@ -88,8 +76,8 @@ module Tabulatr::Finder
|
|
88
76
|
visible_ids = uncompress_id_list(checked_param[:visible])
|
89
77
|
selected_ids = (selected_ids - visible_ids).sort.uniq
|
90
78
|
end
|
91
|
-
|
92
|
-
# at this point, we've retrieved the filter settings, the sorting setting, the pagination settings and
|
79
|
+
|
80
|
+
# at this point, we've retrieved the filter settings, the sorting setting, the pagination settings and
|
93
81
|
# the selected_ids.
|
94
82
|
filter_param = (params[filter_name] || {})
|
95
83
|
sortparam = params[sort_name]
|
@@ -97,12 +85,12 @@ module Tabulatr::Finder
|
|
97
85
|
|
98
86
|
# store the state if appropriate
|
99
87
|
if opts[:stateful]
|
100
|
-
session =
|
88
|
+
session = options[:stateful]
|
101
89
|
sname = "#{cname}#{form_options[:state_session_postfix]}"
|
102
90
|
raise "give the session as the :stateful parameter in find_for_table, not a '#{session.class}'" \
|
103
|
-
unless session.
|
91
|
+
unless session.respond_to? :[]
|
104
92
|
session[sname] ||= {}
|
105
|
-
|
93
|
+
|
106
94
|
if params["#{cname}#{form_options[:reset_state_postfix]}"]
|
107
95
|
# clicked reset button, reset all and clear session
|
108
96
|
selected_ids = []
|
@@ -128,59 +116,49 @@ module Tabulatr::Finder
|
|
128
116
|
|
129
117
|
# firstly, get the conditions from the filters
|
130
118
|
includes = []
|
131
|
-
|
119
|
+
maps = opts[:name_mapping] || {}
|
132
120
|
conditions = filter_param.each do |t|
|
133
121
|
n, v = t
|
134
122
|
next unless v.present?
|
135
123
|
# FIXME n = name_escaping(n)
|
136
124
|
if (n != form_options[:associations_filter])
|
137
|
-
table_name =
|
138
|
-
|
125
|
+
table_name = adapter.table_name
|
126
|
+
nn = if maps[n] then maps[n] else
|
127
|
+
t = "#{table_name}.#{n}"
|
128
|
+
raise "SECURITY violation, field name is '#{t}'" unless /^[\d\w]+(\.[\d\w]+)?$/.match t
|
129
|
+
t
|
130
|
+
end
|
131
|
+
# puts ">>>>>1>> #{n} -> #{nn}"
|
132
|
+
adapter.add_conditions_from(nn, v)
|
139
133
|
else
|
140
134
|
v.each do |t|
|
141
135
|
n,v = t
|
142
136
|
assoc, att = n.split(".").map(&:to_sym)
|
143
|
-
r = klaz.reflect_on_association(assoc)
|
144
137
|
includes << assoc
|
145
|
-
table_name = (
|
146
|
-
nn =
|
147
|
-
|
138
|
+
table_name = adapter.table_name_for_association(assoc)
|
139
|
+
nn = if maps[n] then maps[n] else
|
140
|
+
t = "#{table_name}.#{att}"
|
141
|
+
raise "SECURITY violation, field name is '#{t}'" unless /^[\d\w]+(\.[\d\w]+)?$/.match t
|
142
|
+
t
|
143
|
+
end
|
144
|
+
# puts ">>>>>2>> #{n} -> #{nn}"
|
145
|
+
adapter.add_conditions_from(nn, v)
|
148
146
|
end
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
150
|
+
|
152
151
|
# more button handling
|
153
152
|
if checked_param[:select_filtered]
|
154
|
-
all =
|
153
|
+
all = adapter.all
|
155
154
|
selected_ids = (selected_ids + all.map { |r| i=r.send(id); i.is_a?(Fixnum) ? i : i.to_s }).sort.uniq
|
156
155
|
elsif checked_param[:unselect_filtered]
|
157
|
-
all =
|
156
|
+
all = adapter.dup.all
|
158
157
|
selected_ids = (selected_ids - all.map { |r| i=r.send(id); i.is_a?(Fixnum) ? i : i.to_s }).sort.uniq
|
159
158
|
end
|
160
159
|
|
161
160
|
# secondly, find the order_by stuff
|
162
|
-
|
163
|
-
if sortparam[:_resort]
|
164
|
-
order_by = sortparam[:_resort].first.first
|
165
|
-
order_direction = sortparam[:_resort].first.last.first.first
|
166
|
-
else
|
167
|
-
order_by = sortparam.first.first
|
168
|
-
order_direction = sortparam.first.last.first.first
|
169
|
-
end
|
170
|
-
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\w]+$/.match order_direction
|
171
|
-
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\d\w]+$/.match order_by
|
172
|
-
else
|
173
|
-
if opts[:default_order]
|
174
|
-
l = opts[:default_order].split(" ")
|
175
|
-
raise(":default_order parameter should be of the form 'id asc' or 'name desc'.") \
|
176
|
-
if l.length == 0 or l.length > 2
|
177
|
-
order_by = l[0]
|
178
|
-
order_direction = l[1] || 'asc'
|
179
|
-
else
|
180
|
-
order = order_by = order_direction = nil
|
181
|
-
end
|
182
|
-
end
|
183
|
-
order = (typ==:ar ? "#{order_by} #{order_direction}" : [order_by.to_s, order_direction.to_s]) if order_by
|
161
|
+
order = adapter.order_for_query(sortparam, opts[:default_order])
|
184
162
|
|
185
163
|
# thirdly, get the pagination data
|
186
164
|
paginate_options = Tabulatr.paginate_options.merge(opts).merge(pops)
|
@@ -188,32 +166,33 @@ module Tabulatr::Finder
|
|
188
166
|
page = paginate_options[:page].to_i
|
189
167
|
page += 1 if paginate_options[:page_right]
|
190
168
|
page -= 1 if paginate_options[:page_left]
|
191
|
-
|
169
|
+
|
170
|
+
c = adapter.includes(includes).count
|
192
171
|
# Group statments return a hash
|
193
172
|
c = c.count unless c.class == Fixnum
|
173
|
+
|
194
174
|
pages = (c/pagesize).ceil
|
195
175
|
page = [1, [page, pages].min].max
|
196
|
-
|
197
|
-
total =
|
176
|
+
|
177
|
+
total = adapter.preconditions_scope(opts).count
|
198
178
|
# here too
|
199
|
-
total = total.count
|
200
179
|
total = total.count unless total.class == Fixnum
|
201
|
-
|
180
|
+
|
181
|
+
|
202
182
|
# Now, actually find the stuff
|
203
|
-
found =
|
204
|
-
).order(order).to_a #, :include => includes
|
183
|
+
found = adapter.limit(pagesize.to_i).offset(((page-1)*pagesize).to_i).order(order).to_a
|
205
184
|
|
206
185
|
# finally, inject methods to retrieve the current 'settings'
|
207
|
-
found.define_singleton_method(:__filters)
|
208
|
-
found.define_singleton_method(:__classinfo)
|
186
|
+
found.define_singleton_method(:__filters) { filter_param }
|
187
|
+
found.define_singleton_method(:__classinfo) { [klaz, cname, id, id_type] }
|
209
188
|
found.define_singleton_method(:__pagination) do
|
210
189
|
{ :page => page, :pagesize => pagesize, :count => c, :pages => pages,
|
211
190
|
:pagesizes => paginate_options[:pagesizes],
|
212
191
|
:total => total }
|
213
192
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
193
|
+
|
194
|
+
found.define_singleton_method(:__sorting) { adapter.order(sortparam, opts[:default_order]) }
|
195
|
+
|
217
196
|
visible_ids = (found.map { |r| r.send(id) })
|
218
197
|
checked_ids = compress_id_list(selected_ids - visible_ids)
|
219
198
|
visible_ids = compress_id_list(visible_ids)
|
@@ -223,12 +202,9 @@ module Tabulatr::Finder
|
|
223
202
|
:visible => visible_ids
|
224
203
|
}
|
225
204
|
end
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
found.define_singleton_method(:__store_data) do
|
230
|
-
opts[:store_data] || {}
|
231
|
-
end
|
205
|
+
|
206
|
+
found.define_singleton_method(:__stateful) { (opts[:stateful] ? true : false) }
|
207
|
+
found.define_singleton_method(:__store_data) { opts[:store_data] || {} }
|
232
208
|
|
233
209
|
found
|
234
210
|
end
|
@@ -23,6 +23,7 @@
|
|
23
23
|
|
24
24
|
module Tabulatr::Formattr
|
25
25
|
ALLOWED_METHODS = [:euro, :dollar, :percent, :lamp]
|
26
|
+
#include ActionView::TagHelpers
|
26
27
|
|
27
28
|
def self.format(nam, val)
|
28
29
|
nam = nam.to_sym
|
@@ -45,7 +46,10 @@ module Tabulatr::Formattr
|
|
45
46
|
("%.2f&thinspace;%%" % 100.0*x).gsub(".", ",")
|
46
47
|
end
|
47
48
|
|
48
|
-
def self.lamp(x)
|
49
|
-
|
49
|
+
def self.lamp(x, mapping)
|
50
|
+
s = mapping[x].to_s
|
51
|
+
return "?" unless %w{g y r n}.member?(s)
|
52
|
+
image_tag("tabulatr/#{s}state.gif").html_safe
|
50
53
|
end
|
54
|
+
|
51
55
|
end
|
@@ -98,7 +98,8 @@ class Tabulatr
|
|
98
98
|
:action => nil, # target action of the wrapping form if applicable
|
99
99
|
:batch_actions => false, # :name => value hash of batch action stuff
|
100
100
|
:translate => false, # call t() for all 'labels' and stuff, possible values are true/:translate or :localize
|
101
|
-
:row_classes => ['odd', 'even']
|
101
|
+
:row_classes => ['odd', 'even'], # class for the trs
|
102
|
+
:footer_content => false # if given, add a <%= content_for <footer_content> %> before the </table>
|
102
103
|
})
|
103
104
|
|
104
105
|
# these settings are considered constant for the whole application, can not be overridden
|
@@ -163,7 +164,8 @@ class Tabulatr
|
|
163
164
|
:default_pagesize => false,
|
164
165
|
:precondition => false,
|
165
166
|
:store_data => false,
|
166
|
-
:stateful => false
|
167
|
+
:stateful => false,
|
168
|
+
:name_mapping => nil
|
167
169
|
})
|
168
170
|
|
169
171
|
# Stupid hack
|
data/lib/tabulatr/version.rb
CHANGED
@@ -41,5 +41,5 @@ module DummyApp
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
USE_MONGOID =
|
45
|
-
puts("Using #{USE_MONGOID ? 'Mongoid' : 'ActiveRecord'}")
|
44
|
+
USE_MONGOID = ENV['USE_MONGOID']
|
45
|
+
puts("Using #{USE_MONGOID ? 'Mongoid' : 'ActiveRecord'}")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Tabulatrs" do
|
4
|
-
|
4
|
+
|
5
5
|
Mongoid.master.collections.select do |collection|
|
6
6
|
collection.name !~ /system/
|
7
7
|
end.each(&:drop)
|
@@ -15,23 +15,6 @@ describe "Tabulatrs" do
|
|
15
15
|
"occaecat", "cupidatat", "non", "proident", "sunt", "culpa", "qui",
|
16
16
|
"officia", "deserunt", "mollit", "anim", "est", "laborum"]
|
17
17
|
|
18
|
-
# control which tests to run. Just to spped testing up
|
19
|
-
tralse = true
|
20
|
-
# General stuf
|
21
|
-
WORKS_IN_GENERAL = CONTAINS_BUTTONS = CONTAINS_COLUMN_HEADERS = CONTAINS_OTHER_CONTROLS = tralse
|
22
|
-
# This fills in the data, so rather not cmment this out
|
23
|
-
CONTAINS_ACTUAL_DATA = CONTAINS_ASSOC_DATA = CONTAINS_ACTUAL_DATA_MULTIPLE = CONTAINS_DATA_ON_FURTHER_PAGES = tralse
|
24
|
-
# Paginatione
|
25
|
-
PAGES_UP_AND_DOWN = JUMPS_TO_CORRECT_PAGE = CHANGES_PAGE_SIZE = tralse
|
26
|
-
# Filters
|
27
|
-
FILTERS = FILTERS_WITH_LIKE = FILTERS_WITH_RANGE = tralse
|
28
|
-
# Sorting
|
29
|
-
KNOWS_HOW_TO_SORT = tralse
|
30
|
-
# Statful
|
31
|
-
SORTS_STATEFULLY = FILTERS_STATEFULLY = SELECTS_STATEFULLY = tralse
|
32
|
-
# selecting and batch actions
|
33
|
-
SELECT_BUTTONS_WORK = KNOWS_HOW_TO_SELECT_AND_APPLY_BATCH_ACTIONS = tralse
|
34
|
-
|
35
18
|
vendor1 = Vendor.create!(:name => "ven d'or", :active => true)
|
36
19
|
vendor2 = Vendor.create!(:name => 'producer', :active => true)
|
37
20
|
tag1 = Tag.create!(:title => 'foo')
|
@@ -43,7 +26,7 @@ describe "Tabulatrs" do
|
|
43
26
|
it "works in general" do
|
44
27
|
get index_simple_products_path
|
45
28
|
response.status.should be(200)
|
46
|
-
end
|
29
|
+
end
|
47
30
|
|
48
31
|
it "contains buttons" do
|
49
32
|
visit index_simple_products_path
|
@@ -53,19 +36,19 @@ describe "Tabulatrs" do
|
|
53
36
|
page.should have_button(Tabulatr::TABLE_OPTIONS[n])
|
54
37
|
end
|
55
38
|
page.should_not have_button(Tabulatr::TABLE_OPTIONS[:reset_label])
|
56
|
-
end
|
39
|
+
end
|
57
40
|
|
58
41
|
it "contains column headers" do
|
59
42
|
visit index_simple_products_path
|
60
43
|
['Id','Title','Price','Active','Created At','Vendor Created At','Vendor Name','Tags Title','Tags Count'].each do |n|
|
61
44
|
page.should have_content(n)
|
62
45
|
end
|
63
|
-
end
|
46
|
+
end
|
64
47
|
|
65
48
|
it "contains other elements" do
|
66
49
|
visit index_simple_products_path
|
67
50
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 0, 0, 0, 0))
|
68
|
-
end
|
51
|
+
end
|
69
52
|
|
70
53
|
it "contains the actual data" do
|
71
54
|
product = Product.create!(:title => names[0], :active => true, :price => 10.0, :description => 'blah blah')
|
@@ -81,7 +64,7 @@ describe "Tabulatrs" do
|
|
81
64
|
ids << product.id
|
82
65
|
visit index_simple_products_path
|
83
66
|
page.should have_content("ven d'or")
|
84
|
-
end
|
67
|
+
end
|
85
68
|
|
86
69
|
it "correctly contains the association data" do
|
87
70
|
product = Product.first
|
@@ -91,7 +74,7 @@ describe "Tabulatrs" do
|
|
91
74
|
page.should have_content tag.title
|
92
75
|
page.should have_content(sprintf("--%d--", i+1))
|
93
76
|
end
|
94
|
-
end
|
77
|
+
end
|
95
78
|
|
96
79
|
it "contains the actual data multiple" do
|
97
80
|
9.times do |i|
|
@@ -103,14 +86,14 @@ describe "Tabulatrs" do
|
|
103
86
|
page.should have_content((11.0+i).to_s)
|
104
87
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], i+2, i+2, 0, i+2))
|
105
88
|
end
|
106
|
-
end
|
89
|
+
end
|
107
90
|
|
108
91
|
it "contains row identifiers" do
|
109
92
|
visit index_simple_products_path
|
110
93
|
Product.all.each do |product|
|
111
94
|
page.should have_css("#product_#{product.id}")
|
112
95
|
end
|
113
|
-
end
|
96
|
+
end
|
114
97
|
|
115
98
|
it "contains the further data on the further pages" do
|
116
99
|
names[10..-1].each_with_index do |n,i|
|
@@ -122,7 +105,7 @@ describe "Tabulatrs" do
|
|
122
105
|
page.should_not have_content((30.0+i).to_s)
|
123
106
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 10, i+11, 0, i+11))
|
124
107
|
end
|
125
|
-
end
|
108
|
+
end
|
126
109
|
end
|
127
110
|
|
128
111
|
describe "Pagination" do
|
@@ -163,7 +146,7 @@ describe "Tabulatrs" do
|
|
163
146
|
click_button('product_pagination_page_left')
|
164
147
|
end
|
165
148
|
end
|
166
|
-
end
|
149
|
+
end
|
167
150
|
|
168
151
|
it "jumps to the correct page" do
|
169
152
|
visit index_simple_products_path
|
@@ -187,7 +170,7 @@ describe "Tabulatrs" do
|
|
187
170
|
page.should have_button('product_pagination_page_right')
|
188
171
|
end
|
189
172
|
end
|
190
|
-
end
|
173
|
+
end
|
191
174
|
|
192
175
|
it "changes the page size" do
|
193
176
|
visit index_simple_products_path
|
@@ -199,7 +182,7 @@ describe "Tabulatrs" do
|
|
199
182
|
end
|
200
183
|
page.should_not have_content(names[s])
|
201
184
|
end
|
202
|
-
end
|
185
|
+
end
|
203
186
|
end
|
204
187
|
|
205
188
|
describe "Filters" do
|
@@ -214,7 +197,7 @@ describe "Tabulatrs" do
|
|
214
197
|
click_button("Apply")
|
215
198
|
page.should_not have_content("lorem")
|
216
199
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 0, names.length, 0, 0))
|
217
|
-
end
|
200
|
+
end
|
218
201
|
|
219
202
|
it "filters with like" do
|
220
203
|
visit index_filters_products_path
|
@@ -226,7 +209,7 @@ describe "Tabulatrs" do
|
|
226
209
|
#save_and_open_page
|
227
210
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], [10,tot].min, names.length, 0, tot))
|
228
211
|
end
|
229
|
-
end
|
212
|
+
end
|
230
213
|
|
231
214
|
it "filters with range" do
|
232
215
|
visit index_filters_products_path
|
@@ -250,7 +233,7 @@ describe "Tabulatrs" do
|
|
250
233
|
tot = n-i*2
|
251
234
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], [10,tot].min, n, 0, tot))
|
252
235
|
end
|
253
|
-
end
|
236
|
+
end
|
254
237
|
end
|
255
238
|
|
256
239
|
describe "Sorting" do
|
@@ -269,11 +252,12 @@ describe "Tabulatrs" do
|
|
269
252
|
(1..10).each do |i|
|
270
253
|
page.should have_content snames[i-1]
|
271
254
|
end
|
272
|
-
end
|
255
|
+
end
|
273
256
|
end
|
274
257
|
|
275
258
|
describe "statefulness" do
|
276
259
|
it "sorts statefully" do
|
260
|
+
Capybara.reset_sessions!
|
277
261
|
visit index_stateful_products_path
|
278
262
|
click_button("product_sort_title_desc")
|
279
263
|
snames = names.sort
|
@@ -288,7 +272,7 @@ describe "Tabulatrs" do
|
|
288
272
|
(1..10).each do |i|
|
289
273
|
page.should have_content names[i-1]
|
290
274
|
end
|
291
|
-
end
|
275
|
+
end
|
292
276
|
|
293
277
|
it "filters statefully" do
|
294
278
|
Capybara.reset_sessions!
|
@@ -300,9 +284,10 @@ describe "Tabulatrs" do
|
|
300
284
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 1, names.length, 0, 1))
|
301
285
|
click_button("Reset")
|
302
286
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 10, names.length, 0, names.length))
|
303
|
-
end
|
287
|
+
end
|
304
288
|
|
305
289
|
it "selects statefully" do
|
290
|
+
Capybara.reset_sessions!
|
306
291
|
visit index_stateful_products_path
|
307
292
|
fill_in("product_filter[title]", :with => "")
|
308
293
|
click_button("Apply")
|
@@ -321,7 +306,7 @@ describe "Tabulatrs" do
|
|
321
306
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], names.length % 10, n, tot, n))
|
322
307
|
click_button("Reset")
|
323
308
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 10, names.length, 0, names.length))
|
324
|
-
end
|
309
|
+
end
|
325
310
|
|
326
311
|
end
|
327
312
|
|
@@ -363,7 +348,7 @@ describe "Tabulatrs" do
|
|
363
348
|
fill_in("product_filter[title][like]", :with => "")
|
364
349
|
click_button("Apply")
|
365
350
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 10, n, n-tot, n))
|
366
|
-
end
|
351
|
+
end
|
367
352
|
|
368
353
|
it "knows how to select and apply batch actions" do
|
369
354
|
visit index_select_products_path
|
@@ -382,7 +367,7 @@ describe "Tabulatrs" do
|
|
382
367
|
tot = n-3*(n/10)
|
383
368
|
page.should have_content(sprintf(Tabulatr::TABLE_OPTIONS[:info_text], 10, tot, 0, tot))
|
384
369
|
#save_and_open_page
|
385
|
-
end
|
370
|
+
end
|
386
371
|
end
|
387
372
|
|
388
373
|
# describe "GET /products empty" do
|
data/tabulatr.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
18
|
s.rdoc_options = ['--charset=UTF-8']
|
19
|
-
|
19
|
+
|
20
20
|
|
21
21
|
s.add_runtime_dependency('rails', '>= 3.0.0')
|
22
22
|
s.add_dependency('whiny_hash', '>= 0.0.2')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tabulatr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2012-01-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &70187434600440 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70187434600440
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: whiny_hash
|
28
|
-
requirement: &
|
28
|
+
requirement: &70187434599820 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 0.0.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70187434599820
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: id_stuffer
|
39
|
-
requirement: &
|
39
|
+
requirement: &70187434599320 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: 0.0.1
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70187434599320
|
48
48
|
description: A tight DSL to build tables of ActiveRecord or Mongoid models with sorting,
|
49
49
|
pagination, finding/filtering, selecting and batch actions. Tries to do for tables
|
50
50
|
what formtastic and simple_form did for forms.
|
@@ -92,6 +92,9 @@ files:
|
|
92
92
|
- lib/tabulatr.rb
|
93
93
|
- lib/tabulatr/engine.rb
|
94
94
|
- lib/tabulatr/tabulatr.rb
|
95
|
+
- lib/tabulatr/tabulatr/adapter.rb
|
96
|
+
- lib/tabulatr/tabulatr/adapter/active_record.rb
|
97
|
+
- lib/tabulatr/tabulatr/adapter/mongoid.rb
|
95
98
|
- lib/tabulatr/tabulatr/batch_actions.rb
|
96
99
|
- lib/tabulatr/tabulatr/check_controls.rb
|
97
100
|
- lib/tabulatr/tabulatr/data_cell.rb
|
@@ -200,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
203
|
version: '0'
|
201
204
|
requirements: []
|
202
205
|
rubyforge_project:
|
203
|
-
rubygems_version: 1.8.
|
206
|
+
rubygems_version: 1.8.10
|
204
207
|
signing_key:
|
205
208
|
specification_version: 3
|
206
209
|
summary: A tight DSL to build tables of ActiveRecord or Mongoid models with sorting,
|