tabulatr2 0.6.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +71 -27
- data/app/assets/javascripts/tabulatr/application.js +130 -133
- data/app/assets/stylesheets/tabulatr/application.css.scss +153 -0
- data/app/assets/stylesheets/tabulatr/bootstrap2_fixes.css.scss +24 -0
- data/app/views/tabulatr/_tabulatr_actual_table.html.slim +35 -0
- data/app/views/tabulatr/_tabulatr_batch_actions_menu.html.slim +34 -0
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +84 -0
- data/app/views/tabulatr/_tabulatr_filter_menu.html.slim +30 -0
- data/app/views/tabulatr/_tabulatr_fuzzy_search_field.html.slim +24 -0
- data/app/views/tabulatr/_tabulatr_info_string.html.slim +23 -0
- data/app/views/tabulatr/_tabulatr_paginator.html.slim +24 -0
- data/app/views/tabulatr/_tabulatr_static_table.html.slim +33 -0
- data/app/views/tabulatr/_tabulatr_table.html.slim +45 -0
- data/lib/tabulatr/data/column_name_builder.rb +86 -0
- data/lib/tabulatr/data/data.rb +135 -0
- data/lib/tabulatr/data/dsl.rb +61 -0
- data/lib/tabulatr/data/filtering.rb +101 -0
- data/lib/tabulatr/data/formatting.rb +65 -0
- data/lib/tabulatr/data/invoker.rb +37 -0
- data/lib/tabulatr/data/pagination.rb +48 -0
- data/lib/tabulatr/data/proxy.rb +41 -0
- data/lib/tabulatr/{tabulatr/batch_actions.rb → data/sorting.rb} +20 -23
- data/lib/tabulatr/engine.rb +24 -1
- data/lib/tabulatr/generators/railtie.rb +33 -0
- data/lib/tabulatr/generators/resource_override.rb +35 -0
- data/lib/{generators → tabulatr/generators}/tabulatr/install_generator.rb +21 -3
- data/lib/{generators → tabulatr/generators}/tabulatr/templates/tabulatr.yml +3 -1
- data/lib/tabulatr/generators/tabulatr/templates/tabulatr_data.rb +18 -0
- data/lib/tabulatr/json_builder.rb +94 -0
- data/lib/tabulatr/rails/action_controller.rb +36 -0
- data/lib/{initializers → tabulatr/rails}/action_view.rb +6 -3
- data/lib/{initializers → tabulatr/rails}/active_record.rb +11 -19
- data/lib/tabulatr/renderer/action.rb +32 -0
- data/lib/tabulatr/{tabulatr/formattr.rb → renderer/association.rb} +19 -30
- data/lib/tabulatr/renderer/checkbox.rb +36 -0
- data/lib/tabulatr/renderer/column.rb +113 -0
- data/lib/{initializers/mark_as_localizable.rb → tabulatr/renderer/columns.rb} +13 -15
- data/lib/tabulatr/renderer/columns_from_block.rb +56 -0
- data/lib/tabulatr/renderer/renderer.rb +96 -0
- data/lib/tabulatr/utility/utility.rb +46 -0
- data/lib/tabulatr/version.rb +25 -2
- data/lib/tabulatr.rb +45 -4
- data/lib/tabulatr2.rb +1 -0
- data/spec/dummy/app/assets/stylesheets/application.css.scss +2 -2
- data/spec/dummy/app/controllers/products_controller.rb +27 -3
- data/spec/dummy/app/models/vendor.rb +1 -0
- data/spec/dummy/app/tabulatr_data/product_tabulatr_data.rb +29 -0
- data/spec/dummy/app/views/products/implicit_columns.html.erb +1 -0
- data/spec/dummy/app/views/products/one_item_per_page.html.erb +1 -1
- data/spec/dummy/app/views/products/simple_index.html.erb +6 -4
- data/spec/dummy/app/views/products/stupid_array.html.erb +1 -1
- data/spec/dummy/app/views/products/with_batch_actions.html.erb +10 -0
- data/spec/dummy/config/locales/tabulatr.yml +22 -1
- data/spec/dummy/config/routes.rb +3 -1
- data/spec/features/tabulatrs_spec.rb +53 -11
- data/tabulatr.gemspec +1 -1
- metadata +50 -42
- 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/stylesheets/tabulatr/application.css +0 -40
- data/lib/initializers/action_controller.rb +0 -13
- data/lib/tabulatr/tabulatr/adapter/active_record.rb +0 -84
- data/lib/tabulatr/tabulatr/adapter.rb +0 -55
- data/lib/tabulatr/tabulatr/data_cell.rb +0 -132
- data/lib/tabulatr/tabulatr/dummy_record.rb +0 -40
- data/lib/tabulatr/tabulatr/empty_cell.rb +0 -44
- data/lib/tabulatr/tabulatr/filter_cell.rb +0 -145
- data/lib/tabulatr/tabulatr/filter_icon.rb +0 -6
- data/lib/tabulatr/tabulatr/finder/find_for_table.rb +0 -187
- data/lib/tabulatr/tabulatr/finder.rb +0 -64
- data/lib/tabulatr/tabulatr/header_cell.rb +0 -146
- data/lib/tabulatr/tabulatr/json_builder.rb +0 -57
- data/lib/tabulatr/tabulatr/paginator.rb +0 -76
- data/lib/tabulatr/tabulatr/row_builder.rb +0 -128
- data/lib/tabulatr/tabulatr/security.rb +0 -21
- data/lib/tabulatr/tabulatr/settings.rb +0 -158
- data/lib/tabulatr/tabulatr.rb +0 -343
- data/spec/lib/tabulatr/tabulatr/finder/find_for_table_spec.rb +0 -187
- /data/lib/{generators → tabulatr/generators}/tabulatr/templates/tabulatr.rb +0 -0
@@ -1,145 +0,0 @@
|
|
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
|
-
# the method used to actually define the filters of the columns,
|
27
|
-
# taking the name of the attribute and a hash of options.
|
28
|
-
#
|
29
|
-
# The following options are evaluated here:
|
30
|
-
# <tt>:filter_html</tt>:: a hash with html-attributes added to the <ts>s created
|
31
|
-
# <tt>:filter</tt>:: may take different values:
|
32
|
-
# <tt>false</tt>:: no filter is output for this column
|
33
|
-
# a container:: the keys of the hash are used to define a <tt>select</tt>
|
34
|
-
# where the values are the <tt>value</tt> of the <tt>options</tt>.
|
35
|
-
# an Array:: the elements of that array are used to define a
|
36
|
-
# <tt>select</tt>
|
37
|
-
# a String:: a <tt>select</tt> is created with that String as options
|
38
|
-
# you can use ActionView#collection_select and the like
|
39
|
-
def filter_column(name, opts={}, &block)
|
40
|
-
raise "Not in filter mode!" if @row_mode != :filter
|
41
|
-
opts = normalize_column_options(name, opts)
|
42
|
-
of = opts[:filter]
|
43
|
-
iname = "#{@classname}#{@table_form_options[:filter_postfix]}[#{name}]"
|
44
|
-
filter_name = "tabulatr_form_#{name}"
|
45
|
-
build_filter(of, filter_name, name, iname, opts) if filterable?(of, name.to_s)
|
46
|
-
end
|
47
|
-
|
48
|
-
# the method used to actually define the filters of the columns,
|
49
|
-
# taking the name of the attribute and a hash of options.
|
50
|
-
#
|
51
|
-
# The following options are evaluated here:
|
52
|
-
# <tt>:filter_html</tt>:: a hash with html-attributes added to the <ts>s created
|
53
|
-
# <tt>:filter</tt>:: may take different values:
|
54
|
-
# <tt>false</tt>:: no filter is output for this column
|
55
|
-
# a Hash:: the keys of the hash are used to define a <tt>select</tt>
|
56
|
-
# where the values are the <tt>value</tt> of the <tt>options</tt>.
|
57
|
-
# an Array:: the elements of that array are used to define a
|
58
|
-
# <tt>select</tt>
|
59
|
-
# a subclass of <tt>ActiveRecord::Base</tt>:: a <tt>select</tt> is created
|
60
|
-
# with all instances
|
61
|
-
def filter_association(relation, name, opts={}, &block)
|
62
|
-
raise "Not in filter mode!" if @row_mode != :filter
|
63
|
-
opts = normalize_column_options(name, opts)
|
64
|
-
|
65
|
-
of = opts[:filter]
|
66
|
-
iname = "#{@classname}#{@table_form_options[:filter_postfix]}[#{@table_form_options[:associations_filter]}][#{relation}.#{name}]"
|
67
|
-
filter_name = "tabulatr_form_#{relation}_#{name}"
|
68
|
-
build_filter(of, filter_name, name, iname, opts, relation) if filterable?(of, name.to_s, relation)
|
69
|
-
end
|
70
|
-
|
71
|
-
def filter_checkbox(opts={}, &block)
|
72
|
-
raise "Whatever that's for!" if block_given?
|
73
|
-
make_tag(:td, opts[:filter_html]) {}
|
74
|
-
end
|
75
|
-
|
76
|
-
def filter_action(opts={}, &block)
|
77
|
-
raise "Not in filter mode!" if @row_mode != :filter
|
78
|
-
opts = normalize_column_options(:action_column, opts)
|
79
|
-
make_tag(:td, opts[:filter_html]) do
|
80
|
-
concat(t(opts[:filter])) unless [true, false, nil].member?(opts[:filter])
|
81
|
-
end # </td>
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def filter_tag(of, name, iname, attr_name, opts)
|
87
|
-
if !of
|
88
|
-
""
|
89
|
-
elsif of.is_a?(Hash) or of.is_a?(Array) or of.is_a?(String)
|
90
|
-
make_tag(:select, :style => "width:#{opts[:filter_width]}",
|
91
|
-
:id => name, name: iname) do
|
92
|
-
if of.class.is_a?(String)
|
93
|
-
concat(of)
|
94
|
-
else
|
95
|
-
concat("<option></option>")
|
96
|
-
t = options_for_select(of)
|
97
|
-
concat(t.sub("value=\"\"", "value=\"\" selected=\"selected\""))
|
98
|
-
end
|
99
|
-
end # </select>
|
100
|
-
elsif opts[:filter] == :range
|
101
|
-
filter_text_tag(opts[:filter_width], "#{name}_from", iname, attr_name, 'from')
|
102
|
-
concat(t(opts[:range_filter_symbol]))
|
103
|
-
filter_text_tag(opts[:filter_width], "#{name}_to", iname, attr_name, 'to')
|
104
|
-
elsif opts[:filter] == :checkbox
|
105
|
-
checkbox_value = opts[:checkbox_value]
|
106
|
-
checkbox_label = opts[:checkbox_label]
|
107
|
-
concat(check_box_tag(iname, checkbox_value, false, {}))
|
108
|
-
concat(checkbox_label)
|
109
|
-
elsif opts[:filter] == :exact
|
110
|
-
filter_text_tag(opts[:filter_width], name, iname, attr_name, 'normal')
|
111
|
-
else
|
112
|
-
filter_text_tag(opts[:filter_width], name, iname, attr_name, 'like')
|
113
|
-
end # if
|
114
|
-
end
|
115
|
-
|
116
|
-
def filter_text_tag width, name, iname, attr_name, type=nil
|
117
|
-
name_attribute = iname
|
118
|
-
name_attribute += "[#{type}]" if type && type != 'normal'
|
119
|
-
make_tag(:input, :type => :text, :id => name,
|
120
|
-
:style => "width:#{width}",
|
121
|
-
:value => '',
|
122
|
-
:'data-type' => type,
|
123
|
-
:'data-tabulatr-attribute' => attr_name,
|
124
|
-
:class => 'tabulatr_filter',
|
125
|
-
:name => name_attribute)
|
126
|
-
end
|
127
|
-
|
128
|
-
def build_filter(of, filter_name, name, iname, opts, relation=nil)
|
129
|
-
if of
|
130
|
-
make_tag(:div, class: 'control-group') do
|
131
|
-
make_tag(:label, class: 'control-label', for: filter_name) do
|
132
|
-
concat(t(opts[:header] || readable_name_for(name, relation)), :escape_html)
|
133
|
-
end
|
134
|
-
make_tag(:div, class: 'controls') do
|
135
|
-
filter_tag(of, filter_name, iname, name, opts)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def filterable?(of, name, relation=nil)
|
142
|
-
of && (!(relation && name.to_sym == :count))
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
@@ -1,187 +0,0 @@
|
|
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
|
@@ -1,64 +0,0 @@
|
|
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
|
@@ -1,146 +0,0 @@
|
|
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
|
@@ -1,57 +0,0 @@
|
|
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
|
@@ -1,76 +0,0 @@
|
|
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
|