tabulatr 0.3.0 → 0.4.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.
- 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,
|