tabulatr2 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Changelog.textile +124 -0
- data/Gemfile +21 -0
- data/LICENSE +23 -0
- data/README.md +242 -0
- data/Rakefile +11 -0
- data/app/assets/images/tabulatr/buttons_lite_background.png +0 -0
- data/app/assets/images/tabulatr/pager_arrow_left.gif +0 -0
- data/app/assets/images/tabulatr/pager_arrow_left_off.gif +0 -0
- data/app/assets/images/tabulatr/pager_arrow_right.gif +0 -0
- data/app/assets/images/tabulatr/pager_arrow_right_off.gif +0 -0
- data/app/assets/images/tabulatr/sort_arrow_down.gif +0 -0
- data/app/assets/images/tabulatr/sort_arrow_down_off.gif +0 -0
- data/app/assets/images/tabulatr/sort_arrow_up.gif +0 -0
- data/app/assets/images/tabulatr/sort_arrow_up_off.gif +0 -0
- data/app/assets/javascripts/tabulatr/application.js +452 -0
- data/app/assets/javascripts/tabulatr/jquery.inview.min.js +3 -0
- data/app/assets/javascripts/tabulatr.js +1 -0
- data/app/assets/stylesheets/tabulatr/application.css +40 -0
- data/app/assets/stylesheets/tabulatr.css +4 -0
- data/init.rb +1 -0
- data/lib/generators/tabulatr/install_generator.rb +44 -0
- data/lib/generators/tabulatr/templates/tabulatr.rb +5 -0
- data/lib/generators/tabulatr/templates/tabulatr.yml +14 -0
- data/lib/initializers/action_controller.rb +13 -0
- data/lib/initializers/action_view.rb +31 -0
- data/lib/initializers/active_record.rb +48 -0
- data/lib/initializers/mark_as_localizable.rb +43 -0
- data/lib/tabulatr/engine.rb +3 -0
- data/lib/tabulatr/tabulatr/adapter/active_record.rb +84 -0
- data/lib/tabulatr/tabulatr/adapter.rb +55 -0
- data/lib/tabulatr/tabulatr/batch_actions.rb +51 -0
- data/lib/tabulatr/tabulatr/data_cell.rb +132 -0
- data/lib/tabulatr/tabulatr/dummy_record.rb +40 -0
- data/lib/tabulatr/tabulatr/empty_cell.rb +44 -0
- data/lib/tabulatr/tabulatr/filter_cell.rb +145 -0
- data/lib/tabulatr/tabulatr/filter_icon.rb +6 -0
- data/lib/tabulatr/tabulatr/finder/find_for_table.rb +187 -0
- data/lib/tabulatr/tabulatr/finder.rb +64 -0
- data/lib/tabulatr/tabulatr/formattr.rb +55 -0
- data/lib/tabulatr/tabulatr/header_cell.rb +146 -0
- data/lib/tabulatr/tabulatr/json_builder.rb +57 -0
- data/lib/tabulatr/tabulatr/paginator.rb +76 -0
- data/lib/tabulatr/tabulatr/row_builder.rb +128 -0
- data/lib/tabulatr/tabulatr/security.rb +21 -0
- data/lib/tabulatr/tabulatr/settings.rb +158 -0
- data/lib/tabulatr/tabulatr.rb +343 -0
- data/lib/tabulatr/version.rb +3 -0
- data/lib/tabulatr.rb +34 -0
- data/spec/dummy/.gitignore +18 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/stylesheets/application.css.scss +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/products_controller.rb +24 -0
- data/spec/dummy/app/controllers/tags_controller.rb +5 -0
- data/spec/dummy/app/controllers/vendors_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +9 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/product.rb +5 -0
- data/spec/dummy/app/models/tag.rb +3 -0
- data/spec/dummy/app/models/vendor.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/products/count_tags.html.erb +9 -0
- data/spec/dummy/app/views/products/one_item_per_page.html.erb +9 -0
- data/spec/dummy/app/views/products/simple_index.html.erb +9 -0
- data/spec/dummy/app/views/products/stupid_array.html.erb +20 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/tabulatr.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/locales/tabulatr.yml +14 -0
- data/spec/dummy/config/routes.rb +13 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20130730132101_create_vendors.rb +12 -0
- data/spec/dummy/db/migrate/20130730132321_create_products.rb +12 -0
- data/spec/dummy/db/migrate/20130730132348_create_tags.rb +14 -0
- data/spec/dummy/db/schema.rb +47 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/features/tabulatrs_spec.rb +227 -0
- data/spec/lib/tabulatr/tabulatr/finder/find_for_table_spec.rb +187 -0
- data/spec/spec_helper.rb +45 -0
- data/tabulatr.gemspec +29 -0
- metadata +258 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# These are extensions for use from ActionController instances
|
25
|
+
# In a seperate class call only for clearity
|
26
|
+
|
27
|
+
require 'activerecord_outer_joins'
|
28
|
+
|
29
|
+
module Tabulatr::Finder
|
30
|
+
|
31
|
+
# -------------------------------------------------------------------
|
32
|
+
# Called if SomeActveRecordSubclass::find_for_table(params) is called
|
33
|
+
#
|
34
|
+
def self.find_for_table(klaz, params, options={}, &block)
|
35
|
+
adapter = if klaz.respond_to?(:descends_from_active_record?) then ::Tabulatr::Adapter::ActiveRecordAdapter.new(klaz)
|
36
|
+
else raise("Don't know how to deal with class '#{klaz}'")
|
37
|
+
end
|
38
|
+
|
39
|
+
Tabulatr::Security.validate!("#{params[:arguments]}-#{params[:salt]}-#{params[:hash]}")
|
40
|
+
|
41
|
+
form_options = Tabulatr.table_form_options
|
42
|
+
opts = Tabulatr.finder_options.merge(options)
|
43
|
+
params ||= {} # just to be sure
|
44
|
+
cname = adapter.class_to_param
|
45
|
+
sort_name = "#{cname}#{form_options[:sort_postfix]}"
|
46
|
+
filter_name = "#{cname}#{form_options[:filter_postfix]}"
|
47
|
+
batch_name = "#{cname}#{form_options[:batch_postfix]}"
|
48
|
+
check_name = "tabulatr_checked"
|
49
|
+
append = params[:append].present? ? params[:append] : false
|
50
|
+
|
51
|
+
|
52
|
+
append = string_to_boolean append
|
53
|
+
# before we do anything else, we find whether there's something to do for batch actions
|
54
|
+
checked_param = ActiveSupport::HashWithIndifferentAccess.new({:checked_ids => '', :current_page => []}).
|
55
|
+
merge(params[check_name] || {})
|
56
|
+
|
57
|
+
id = adapter.primary_key
|
58
|
+
|
59
|
+
serializer = options[:serializer].presence
|
60
|
+
|
61
|
+
# checkboxes
|
62
|
+
checked_ids = checked_param[:checked_ids]
|
63
|
+
selected_ids = checked_ids.split(',')
|
64
|
+
|
65
|
+
execute_batch_actions(params[batch_name], selected_ids, &block)
|
66
|
+
|
67
|
+
# at this point, we've retrieved the filter settings, the sorting setting, the pagination settings and
|
68
|
+
# the selected_ids.
|
69
|
+
filter_param = (params[filter_name] || {})
|
70
|
+
sortparam = params[sort_name]
|
71
|
+
|
72
|
+
includes = []
|
73
|
+
maps = klaz.tabulatr_name_mappings.merge(opts[:name_mapping] || {})
|
74
|
+
|
75
|
+
build_conditions(filter_param, form_options, includes, adapter, maps)
|
76
|
+
order = build_order(params[:sort_by], params[:orientation], params[:default_order], maps, adapter, klaz)
|
77
|
+
|
78
|
+
c = adapter.includes(includes).references(includes).count
|
79
|
+
# Group statments return a hash
|
80
|
+
c = c.count unless c.class == Fixnum
|
81
|
+
pagesize = params[:pagesize]
|
82
|
+
pagination_data = build_offset(params[:page], pagesize, c, opts)
|
83
|
+
|
84
|
+
total = adapter.preconditions_scope(opts).count
|
85
|
+
# here too
|
86
|
+
total = total.count unless total.class == Fixnum
|
87
|
+
|
88
|
+
# Now, actually find the stuff
|
89
|
+
opts[:name_mapping] ||= {}
|
90
|
+
find_on = (klaz.tabulatr_select_attributes(opts[:name_mapping]).try do |s| adapter.select(s) end) || adapter
|
91
|
+
found = find_on.outer_joins(includes)
|
92
|
+
.limit(pagination_data[:pagesize]).offset(pagination_data[:offset])
|
93
|
+
.order(order).to_a
|
94
|
+
|
95
|
+
found.define_singleton_method(:__pagination) do
|
96
|
+
{ :page => pagination_data[:page],
|
97
|
+
:pagesize => pagination_data[:pagesize],
|
98
|
+
:count => c,
|
99
|
+
:pages => pagination_data[:pages],
|
100
|
+
:pagesizes => {},
|
101
|
+
:total => total,
|
102
|
+
:append => append,
|
103
|
+
:table_id => params[:table_id] }
|
104
|
+
end
|
105
|
+
|
106
|
+
found.define_singleton_method(:to_tabulatr_json) do |klass=nil|
|
107
|
+
Tabulatr::JsonBuilder.build found, klass, params[:arguments], id
|
108
|
+
end
|
109
|
+
|
110
|
+
found
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def self.execute_batch_actions batch_param, selected_ids, &block
|
116
|
+
if batch_param.present? && block_given?
|
117
|
+
batch_param = batch_param.keys.first.to_sym if batch_param.is_a?(Hash)
|
118
|
+
yield(Invoker.new(batch_param, selected_ids))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.build_conditions filter_param, form_options, includes, adapter, maps
|
123
|
+
filter_param.each do |filter|
|
124
|
+
name, value = filter
|
125
|
+
next unless value.present?
|
126
|
+
if (name != form_options[:associations_filter])
|
127
|
+
table_name = adapter.table_name
|
128
|
+
nn = extract_column_name(table_name, name, maps)
|
129
|
+
adapter.add_conditions_from(nn, value)
|
130
|
+
else
|
131
|
+
value.each do |assoc_filter|
|
132
|
+
name,value = assoc_filter
|
133
|
+
assoc, att = name.split(".").map(&:to_sym)
|
134
|
+
includes << assoc
|
135
|
+
table_name = adapter.table_name_for_association(assoc)
|
136
|
+
nn = extract_column_name(table_name, name, maps, att)
|
137
|
+
adapter.add_conditions_from(nn, value)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.extract_column_name(table_name, n, maps, att=nil)
|
144
|
+
if maps[n.to_sym]
|
145
|
+
maps[n.to_sym]
|
146
|
+
else
|
147
|
+
if att
|
148
|
+
t = "#{table_name}.#{att}"
|
149
|
+
else
|
150
|
+
t = "#{table_name}.#{n}"
|
151
|
+
end
|
152
|
+
raise "SECURITY violation, field name is '#{t}'" unless /^[\d\w]+(\.[\d\w]+)?$/.match t
|
153
|
+
t
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.build_order sort_by, orientation, default_order, maps, adapter, klaz
|
158
|
+
if sort_by.present?
|
159
|
+
s_by = maps[sort_by] ? maps[sort_by] : sort_by
|
160
|
+
adapter.order_for_query_new s_by, orientation
|
161
|
+
else
|
162
|
+
default_order || "#{klaz.table_name}.#{klaz.primary_key} asc"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.build_offset page, pagesize=10, count, opts
|
167
|
+
page ||= 1
|
168
|
+
pagesize, page = pagesize.to_i, page.to_i
|
169
|
+
pagesize = 10 if pagesize == 0
|
170
|
+
|
171
|
+
pages = (count/pagesize.to_f).ceil
|
172
|
+
|
173
|
+
{offset: ((page-1)*pagesize).to_i, pagesize: pagesize.to_i, pages: pages,
|
174
|
+
page: page
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.string_to_boolean str
|
179
|
+
if str == 'true'
|
180
|
+
str = true
|
181
|
+
elsif str == 'false'
|
182
|
+
str = false
|
183
|
+
end
|
184
|
+
str
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# These are extensions for use from ActionController instances
|
25
|
+
module Tabulatr::Finder
|
26
|
+
|
27
|
+
require File.join(File.dirname(__FILE__), 'finder', 'find_for_table')
|
28
|
+
|
29
|
+
# compress the list of ids as good as I could imagine ;)
|
30
|
+
# uses fancy base twisting
|
31
|
+
def self.compress_id_list(list)
|
32
|
+
if list.length == 0
|
33
|
+
""
|
34
|
+
else
|
35
|
+
"GzB" + Base64.encode64(
|
36
|
+
Zlib::Deflate.deflate(
|
37
|
+
list.join(Tabulatr.table_form_options[:checked_separator])))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# inverse of compress_id_list
|
42
|
+
def self.uncompress_id_list(str)
|
43
|
+
if !str.present?
|
44
|
+
[]
|
45
|
+
elsif str.starts_with?("GzB")
|
46
|
+
Zlib::Inflate.inflate(Base64.decode64(str[3..-1])).split(
|
47
|
+
Tabulatr.table_form_options[:checked_separator])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Invoker
|
52
|
+
def initialize(batch_action, ids)
|
53
|
+
@batch_action = batch_action.to_sym
|
54
|
+
@ids = ids
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_missing(name, *args, &block)
|
58
|
+
if @batch_action == name
|
59
|
+
yield(@ids)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
module Tabulatr::Formattr
|
25
|
+
ALLOWED_METHODS = [:euro, :dollar, :percent, :lamp]
|
26
|
+
#include ActionView::TagHelpers
|
27
|
+
|
28
|
+
def self.format(nam, val)
|
29
|
+
nam = nam.to_sym
|
30
|
+
if ALLOWED_METHODS.member?(nam)
|
31
|
+
self.send nam, val
|
32
|
+
else
|
33
|
+
"[Requested unautorized format '#{nam}' for '#{val}'.]"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.euro(x)
|
38
|
+
("%.2f €" % x).gsub(".", ",")
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.dollar(x)
|
42
|
+
"$ %.2f" % x
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.percent(x)
|
46
|
+
("%.2f&thinspace;%%" % 100.0*x).gsub(".", ",")
|
47
|
+
end
|
48
|
+
|
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
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
|
27
|
+
# the method used to actually define the headers of the columns,
|
28
|
+
# taking the name of the attribute and a hash of options.
|
29
|
+
#
|
30
|
+
# The following options are evaluated here:
|
31
|
+
# <tt>:th_html</tt>:: a hash with html-attributes added to the <th>s created
|
32
|
+
# <tt>:header</tt>:: if present, the value will be output in the header cell,
|
33
|
+
# otherwise, the capitalized name is used
|
34
|
+
def header_column(name, opts={}, &block)
|
35
|
+
raise "Not in header mode!" if @row_mode != :header
|
36
|
+
sortparam = "#{@classname}#{@table_form_options[:sort_postfix]}"
|
37
|
+
filter_name = "#{@classname}#{@table_form_options[:filter_postfix]}[#{name}]"
|
38
|
+
bid = "#{@classname}#{@table_form_options[:sort_postfix]}"
|
39
|
+
|
40
|
+
create_header_tag(name, opts, sortparam, filter_name, name,
|
41
|
+
nil, bid
|
42
|
+
)
|
43
|
+
# opts = normalize_column_options(name, opts)
|
44
|
+
# opts = normalize_header_column_options opts
|
45
|
+
# opts[:th_html]['data-tabulatr-column-name'] = name
|
46
|
+
# opts[:th_html]['data-tabulatr-form-name'] = filter_name
|
47
|
+
# opts[:th_html]['data-tabulatr-sorting-name'] = "#{@klass.table_name}.#{name}"
|
48
|
+
# make_tag(:th, opts[:th_html]) do
|
49
|
+
# concat(t(opts[:header] || readable_name_for(name)), :escape_html)
|
50
|
+
# create_sorting_elements opts, sortparam, name, bid
|
51
|
+
# end # </th>
|
52
|
+
end
|
53
|
+
|
54
|
+
# the method used to actually define the headers of the columns,
|
55
|
+
# taking the name of the attribute and a hash of options.
|
56
|
+
#
|
57
|
+
# The following options are evaluated here:
|
58
|
+
# <tt>:th_html</tt>:: a hash with html-attributes added to the <th>s created
|
59
|
+
# <tt>:header</tt>:: if present, the value will be output in the header cell,
|
60
|
+
# otherwise, the capitalized name is used
|
61
|
+
def header_association(relation, name, opts={}, &block)
|
62
|
+
raise "Not in header mode!" if @row_mode != :header
|
63
|
+
create_header_tag(name, opts,
|
64
|
+
"#{@classname}#{@table_form_options[:sort_postfix]}[#{relation.to_s}.#{name.to_s}]",
|
65
|
+
"#{@classname}#{@table_form_options[:filter_postfix]}[#{@table_form_options[:associations_filter]}][#{relation.to_s}.#{name.to_s}]",
|
66
|
+
"#{relation}:#{name}",
|
67
|
+
relation
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def header_checkbox(opts={}, &block)
|
72
|
+
raise "Whatever that's for!" if block_given?
|
73
|
+
opts = normalize_column_options(:checkbox_column, opts)
|
74
|
+
opts = normalize_header_column_options opts, :checkbox
|
75
|
+
make_tag(:th, opts[:th_html]) do
|
76
|
+
make_tag(:input, type: 'checkbox', :'data-table' => "#{@klass.to_s.downcase}_table",
|
77
|
+
class: "tabulatr_mark_all"){}
|
78
|
+
render_batch_actions if @table_options[:batch_actions]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def header_action(opts={}, &block)
|
83
|
+
raise "Please specify a block" unless block_given?
|
84
|
+
opts = normalize_column_options(:action_column, opts)
|
85
|
+
opts = normalize_header_column_options opts, :action
|
86
|
+
dummy = DummyRecord.for(@klass)
|
87
|
+
cont = yield(dummy)
|
88
|
+
cont = cont.join(' ') if cont.is_a? Array
|
89
|
+
opts[:th_html]['data-tabulatr-action'] = cont.gsub('"', "'")
|
90
|
+
@attributes = (@attributes + dummy.requested_methods).flatten
|
91
|
+
names = dummy.requested_methods.join(',')
|
92
|
+
|
93
|
+
make_tag(:th, opts[:th_html].merge('data-tabulatr-column-name' => names)) do
|
94
|
+
concat(t(opts[:header] || ""), :escape_html)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def normalize_header_column_options opts, type=nil
|
101
|
+
opts[:th_html] ||= {}
|
102
|
+
opts[:th_html]['data-tabulatr-column-type'] = type if type
|
103
|
+
if opts[:format_methods]
|
104
|
+
opts[:th_html]['data-tabulatr-methods'] = opts[:format_methods].join(',')
|
105
|
+
end
|
106
|
+
opts
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_sorting_elements opts, sortparam, name, bid=""
|
110
|
+
if opts[:sortable] and @table_options[:sortable]
|
111
|
+
if @sorting and @sorting[:by].to_s == name.to_s
|
112
|
+
pname = "#{sortparam}[_resort][#{name}]"
|
113
|
+
bid = "#{bid}_#{name}"
|
114
|
+
sort_dir = @sorting[:direction] == 'asc' ? 'desc' : 'asc'
|
115
|
+
make_tag(:input, :type => :hidden,
|
116
|
+
:name => "#{sortparam}[#{name}][#{@sorting[:direction]}]",
|
117
|
+
:value => "#{@sorting[:direction]}")
|
118
|
+
else
|
119
|
+
pname = "#{sortparam}[_resort][#{name}]"
|
120
|
+
bid = "#{bid}_#{name}"
|
121
|
+
sort_dir = 'desc'
|
122
|
+
end
|
123
|
+
make_image_button(:id => bid, :name => pname, :'data-sort' => sort_dir)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def create_header_tag name, opts, sort_param, filter_name, column_name, relation=nil, bid=nil
|
129
|
+
opts = normalize_column_options(name, opts)
|
130
|
+
opts = normalize_header_column_options(opts)
|
131
|
+
opts[:th_html]['data-tabulatr-column-name'] = column_name
|
132
|
+
opts[:th_html]['data-tabulatr-form-name'] = filter_name
|
133
|
+
opts[:th_html]['data-tabulatr-sorting-name'] = sorting_name(name, relation)
|
134
|
+
make_tag(:th, opts[:th_html]) do
|
135
|
+
concat(t(opts[:header] || readable_name_for(name, relation)), :escape_html)
|
136
|
+
create_sorting_elements(opts, sort_param, name, bid) unless relation && name.to_sym == :count
|
137
|
+
end # </th>
|
138
|
+
end
|
139
|
+
|
140
|
+
def sorting_name name, relation=nil
|
141
|
+
return "#{@klass.reflect_on_association(relation).table_name}.#{name}" if relation && @klass.reflect_on_association(relation).klass.column_names.include?(name.to_s)
|
142
|
+
return "#{@klass.table_name}.#{name}" if @klass.column_names.include?(name.to_s)
|
143
|
+
name
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tabulatr::JsonBuilder
|
2
|
+
def self.build(data, klass, requested_attributes, id)
|
3
|
+
if klass && ActiveModel.const_defined?(:ArraySerializer)
|
4
|
+
ActiveModel::ArraySerializer.new(data,
|
5
|
+
{ root: "data", meta: data.__pagination,
|
6
|
+
each_serializer: klass
|
7
|
+
}).as_json
|
8
|
+
else
|
9
|
+
id_included = false
|
10
|
+
attrs = build_hash_from requested_attributes, id
|
11
|
+
result = []
|
12
|
+
data.each do |f|
|
13
|
+
tmp = {}
|
14
|
+
attrs.each do |at|
|
15
|
+
insert_attribute_in_hash(at, f, tmp)
|
16
|
+
end
|
17
|
+
result << tmp
|
18
|
+
end
|
19
|
+
{ data: result, meta: data.__pagination }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def self.build_hash_from requested_attributes, id
|
26
|
+
attrs = []
|
27
|
+
id_included = false
|
28
|
+
requested_attributes.split(',').each do |par|
|
29
|
+
if par.include? ':'
|
30
|
+
relation, action = par.split(':')
|
31
|
+
attrs << {action: action, relation: relation}
|
32
|
+
else
|
33
|
+
id_included = true if par == id
|
34
|
+
attrs << {action: par}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
attrs << {action: id} unless id_included
|
38
|
+
attrs
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.insert_attribute_in_hash at, f, r={}
|
42
|
+
if at.has_key? :relation
|
43
|
+
if f.class.reflect_on_association(at[:relation].to_sym).collection?
|
44
|
+
if at[:action].to_sym == :count
|
45
|
+
r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).count
|
46
|
+
else
|
47
|
+
r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).map(&at[:action].to_sym).join(', ')
|
48
|
+
end
|
49
|
+
else
|
50
|
+
r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).try(at[:action])
|
51
|
+
end
|
52
|
+
else
|
53
|
+
r[at[:action]] = f.send at[:action]
|
54
|
+
end
|
55
|
+
r
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
#render the paginator controls, inputs etc.
|
27
|
+
def render_paginator
|
28
|
+
# get the current pagination state
|
29
|
+
if (@table_options[:paginate].is_a?(Fixnum)) && @klass.count > @table_options[:paginate] ||
|
30
|
+
@table_options[:paginate] === true
|
31
|
+
send(Tabulatr.bootstrap_paginator)
|
32
|
+
end
|
33
|
+
make_tag(:div, :class => 'btn-group tabulatr-per-page', :'data-table' => "#{@klass.to_s.downcase}_table") do
|
34
|
+
make_tag(:button, :class => 'btn') do
|
35
|
+
concat(I18n.t('tabulatr.rows_per_page'))
|
36
|
+
end
|
37
|
+
make_tag(:button, :class => 'btn dropdown-toggle', :'data-toggle' => 'dropdown') do
|
38
|
+
make_tag(:span, :class => 'caret'){}
|
39
|
+
end
|
40
|
+
make_tag(:ul, :class => 'dropdown-menu') do
|
41
|
+
[10, 25, 50, 100].push(@table_options[:default_pagesize]).uniq.sort.each do |n|
|
42
|
+
create_pagination_select(n, n == @table_options[:default_pagesize])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_pagination_select n, default=false
|
49
|
+
make_tag(:li) do
|
50
|
+
params = { :href => "javascript: void(0);",
|
51
|
+
:'data-items-per-page' => n }
|
52
|
+
params[:class] = 'active' if default
|
53
|
+
make_tag(:a, params) do
|
54
|
+
concat(n)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# bootstrap 3
|
62
|
+
def create_ul_paginator
|
63
|
+
make_tag(:ul, :class => @table_options[:paginator_div_class],
|
64
|
+
:'data-table' => "#{@klass.to_s.downcase}_table") do
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# bootstrap 2
|
69
|
+
def create_div_paginator
|
70
|
+
make_tag(:div, :class => @table_options[:paginator_div_class],
|
71
|
+
:'data-table' => "#{@klass.to_s.downcase}_table") do
|
72
|
+
make_tag(:ul){}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|