tabulatr2 0.9.4 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/Gemfile +1 -2
- data/README.md +155 -95
- data/app/assets/javascripts/tabulatr/_storage.js +41 -0
- data/app/assets/javascripts/tabulatr/_tabulatr.js +598 -0
- data/app/assets/javascripts/tabulatr/application.js +3 -553
- data/app/assets/stylesheets/tabulatr/application.css.scss +21 -12
- data/app/assets/stylesheets/tabulatr.css +1 -0
- data/app/views/tabulatr/_tabulatr_actual_table.html.slim +18 -18
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_fuzzy_search_field.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_static_table.html.slim +3 -3
- data/app/views/tabulatr/_tabulatr_table.html.slim +17 -12
- data/lib/tabulatr/data/data.rb +7 -9
- data/lib/tabulatr/data/dsl.rb +36 -21
- data/lib/tabulatr/data/filtering.rb +41 -13
- data/lib/tabulatr/data/formatting.rb +7 -20
- data/lib/tabulatr/data/pagination.rb +1 -2
- data/lib/tabulatr/data/proxy.rb +2 -0
- data/lib/tabulatr/data/sorting.rb +24 -13
- data/lib/tabulatr/engine.rb +1 -0
- data/lib/tabulatr/generators/tabulatr/templates/tabulatr.yml +2 -2
- data/lib/tabulatr/json_builder.rb +23 -25
- data/lib/tabulatr/rails/action_controller.rb +4 -0
- data/lib/tabulatr/rails/action_view.rb +3 -2
- data/lib/tabulatr/renderer/checkbox.rb +3 -1
- data/lib/tabulatr/renderer/column.rb +47 -5
- data/lib/tabulatr/renderer/columns_from_block.rb +24 -6
- data/lib/tabulatr/renderer/renderer.rb +26 -17
- data/lib/tabulatr/utility/unexpected_search_result_error.rb +9 -0
- data/lib/tabulatr/utility/utility.rb +4 -0
- data/lib/tabulatr/version.rb +1 -1
- data/spec/dummy/app/controllers/products_controller.rb +9 -0
- data/spec/dummy/app/views/products/local_storage.html.slim +4 -0
- data/spec/dummy/app/views/products/simple_index.html.erb +1 -1
- data/spec/dummy/app/views/products/stupid_array.html.erb +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/locales/tabulatr.yml +2 -2
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/features/tabulatrs_spec.rb +27 -27
- data/spec/lib/tabulatr/data/data_spec.rb +12 -16
- data/spec/lib/tabulatr/data/filtering_spec.rb +48 -7
- data/spec/lib/tabulatr/data/formatting_spec.rb +32 -0
- data/spec/lib/tabulatr/data/sorting_spec.rb +81 -0
- data/spec/lib/tabulatr/json_builder_spec.rb +23 -9
- data/spec/lib/tabulatr/renderer/checkbox_spec.rb +14 -0
- data/spec/lib/tabulatr/renderer/renderer_spec.rb +20 -8
- data/tabulatr.gemspec +4 -3
- metadata +45 -9
- data/lib/tabulatr/data/column_name_builder.rb +0 -86
@@ -19,15 +19,15 @@
|
|
19
19
|
/ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
/ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
21
|
|
22
|
-
table
|
22
|
+
table class="#{table_options[:html_class]} tabulatr_static_table"
|
23
23
|
thead
|
24
24
|
tr
|
25
25
|
- columns.each do |column|
|
26
|
-
th data-tabulatr-column-name=column.full_name style=column.
|
26
|
+
th data-tabulatr-column-name=column.full_name style=column.html_header_style
|
27
27
|
= column.human_name
|
28
28
|
tbody
|
29
29
|
- records.each do |record|
|
30
30
|
tr data-id=record.try(:id)
|
31
31
|
- columns.each do |column|
|
32
|
-
td data-tabulatr-column-name=column.full_name data-tabulatr-type=column.coltype style=column.
|
32
|
+
td data-tabulatr-column-name=column.full_name data-tabulatr-type=column.coltype style=column.html_cell_style
|
33
33
|
= column.value_for(record, self)
|
@@ -23,24 +23,29 @@
|
|
23
23
|
klass: klass, classname: classname, table_id: table_id,
|
24
24
|
formatted_name: formatted_name }
|
25
25
|
|
26
|
-
.tabulatr-table-controls-wrapper data-table-id=table_id
|
27
|
-
.tabulatr-filter-menu-wrapper data-table-id=table_id
|
26
|
+
.tabulatr-table-controls-wrapper.row data-table-id=table_id
|
27
|
+
.tabulatr-filter-menu-wrapper.col-xs-3.col-sm-1 data-table-id=table_id
|
28
28
|
= render '/tabulatr/tabulatr_filter_menu', opts
|
29
29
|
|
30
|
-
.tabulatr-batch-actions-menu-wrapper data-table-id=table_id
|
30
|
+
.tabulatr-batch-actions-menu-wrapper.col-xs-3.col-sm-1 data-table-id=table_id
|
31
31
|
= render '/tabulatr/tabulatr_batch_actions_menu', opts
|
32
32
|
|
33
|
-
.tabulatr-paginator-wrapper data-table-id=table_id
|
34
|
-
= render '/tabulatr/tabulatr_paginator', opts
|
35
|
-
|
36
|
-
.tabulatr-info-string-wrapper data-table-id=table_id
|
37
|
-
= render '/tabulatr/tabulatr_info_string', opts
|
38
|
-
|
39
33
|
- if tabulatr_data.search?
|
40
|
-
.tabulatr-fuzzy-search-field-wrapper data-table-id=table_id
|
34
|
+
.tabulatr-fuzzy-search-field-wrapper.col-xs-6.col-sm-2 data-table-id=table_id
|
41
35
|
= render '/tabulatr/tabulatr_fuzzy_search_field', opts
|
42
36
|
|
43
|
-
|
44
|
-
|
37
|
+
- if table_options[:pagination_position].in?([:top, :both])
|
38
|
+
.tabulatr-paginator-wrapper.col-xs-12.col-sm-8 data-table-id=table_id
|
39
|
+
= render '/tabulatr/tabulatr_paginator', opts
|
40
|
+
|
41
|
+
|
42
|
+
.tabulatr-filter-dialog-wrapper data-table-id=table_id
|
43
|
+
= render '/tabulatr/tabulatr_filter_dialog', opts
|
44
|
+
|
45
|
+
.tabulatr-info-string-wrapper data-table-id=table_id
|
46
|
+
= render '/tabulatr/tabulatr_info_string', opts
|
45
47
|
|
46
48
|
= render '/tabulatr/tabulatr_actual_table', opts
|
49
|
+
- if table_options[:pagination_position].in?([:bottom, :both])
|
50
|
+
.tabulatr-paginator-wrapper.col-xs-12 data-table-id=table_id
|
51
|
+
= render '/tabulatr/tabulatr_paginator', opts
|
data/lib/tabulatr/data/data.rb
CHANGED
@@ -27,9 +27,7 @@ class Tabulatr::Data
|
|
27
27
|
@relation = relation
|
28
28
|
@base = relation.respond_to?(:klass) ? relation.klass : relation
|
29
29
|
@table_name = @base.table_name
|
30
|
-
@
|
31
|
-
@columns = self.class.instance_variable_get('@columns') || HashWithIndifferentAccess.new
|
32
|
-
@search = self.class.instance_variable_get('@search') || HashWithIndifferentAccess.new
|
30
|
+
@search = self.class.instance_variable_get('@search') || HashWithIndifferentAccess.new
|
33
31
|
@includes = Set.new()
|
34
32
|
@cname = @base.name.downcase
|
35
33
|
@batch_actions = nil
|
@@ -56,7 +54,7 @@ class Tabulatr::Data
|
|
56
54
|
join_required_tables(params)
|
57
55
|
|
58
56
|
pagination = compute_pagination(params[:page], params[:pagesize])
|
59
|
-
apply_pagination(pagination)
|
57
|
+
apply_pagination(pagination.slice(:offset, :pagesize))
|
60
58
|
|
61
59
|
# TODO: batch actions and checked ids
|
62
60
|
|
@@ -104,10 +102,10 @@ class Tabulatr::Data
|
|
104
102
|
# Params
|
105
103
|
#++
|
106
104
|
|
107
|
-
def filter_params(params) params["#{@
|
108
|
-
def search_param(params) params["#{@
|
109
|
-
def sort_params(params) params["#{@
|
110
|
-
def batch_params(params) params["#{@
|
105
|
+
def filter_params(params) params["#{Tabulatr::Utility.formatted_name(@base.name)}_filter"] end
|
106
|
+
def search_param(params) params["#{Tabulatr::Utility.formatted_name(@base.name)}_search"] end
|
107
|
+
def sort_params(params) params["#{Tabulatr::Utility.formatted_name(@base.name)}_sort"] end
|
108
|
+
def batch_params(params) params["#{Tabulatr::Utility.formatted_name(@base.name)}_batch"] end
|
111
109
|
def check_params(params)
|
112
110
|
tabulatr_checked = params["tabulatr_checked"]
|
113
111
|
if tabulatr_checked.present?
|
@@ -119,6 +117,7 @@ class Tabulatr::Data
|
|
119
117
|
tt = (params[:arguments].split(",").select{|s| s[':']}.map do |s|
|
120
118
|
s.split(':').first
|
121
119
|
end.uniq.map(&:to_sym))
|
120
|
+
tt.delete(@table_name.to_sym)
|
122
121
|
@includes = @includes + tt
|
123
122
|
# @relation = @relation.includes(@includes.map(&:to_sym)).references(@includes.map(&:to_sym))
|
124
123
|
@relation = @relation.eager_load(@includes.map(&:to_sym))
|
@@ -132,7 +131,6 @@ class Tabulatr::Data
|
|
132
131
|
|
133
132
|
end
|
134
133
|
|
135
|
-
require_relative './column_name_builder'
|
136
134
|
require_relative './dsl'
|
137
135
|
require_relative './filtering'
|
138
136
|
require_relative './invoker'
|
data/lib/tabulatr/data/dsl.rb
CHANGED
@@ -23,35 +23,50 @@
|
|
23
23
|
|
24
24
|
module Tabulatr::Data::DSL
|
25
25
|
|
26
|
+
def target_class(name)
|
27
|
+
s = name.to_s
|
28
|
+
@target_class = s.camelize.constantize rescue "There's no class `#{s.camelize}' for `#{self.name}'"
|
29
|
+
@target_class_name = s.underscore
|
30
|
+
end
|
31
|
+
|
32
|
+
def main_class
|
33
|
+
target_class_name # to get auto setting @target_class
|
34
|
+
@target_class
|
35
|
+
end
|
36
|
+
|
37
|
+
def target_class_name
|
38
|
+
return @target_class_name if @target_class_name.present?
|
39
|
+
if (s = /(.+)TabulatrData\Z/.match(self.name))
|
40
|
+
# try whether it's a class
|
41
|
+
target_class s[1].underscore
|
42
|
+
else
|
43
|
+
raise "Don't know which class should be target_class for `#{self.name}'."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
26
47
|
def column(name, sort_sql: nil, filter_sql: nil, sql: nil, table_column_options: {}, &block)
|
27
|
-
@columns ||= HashWithIndifferentAccess.new
|
28
|
-
table_column = Tabulatr::Renderer::Column.from(table_column_options.merge(name: name, klass: @base))
|
29
48
|
@table_columns ||= []
|
49
|
+
table_name = main_class.table_name
|
50
|
+
table_column = Tabulatr::Renderer::Column.from(
|
51
|
+
table_column_options.merge(name: name,
|
52
|
+
klass: @base, sort_sql: sort_sql || sql || "#{table_name}.#{name}",
|
53
|
+
filter_sql: filter_sql || sql || "#{table_name}.#{name}",
|
54
|
+
table_name: table_name.to_sym,
|
55
|
+
output: block_given? ? block : ->(record){record.send(name)}))
|
30
56
|
@table_columns << table_column
|
31
|
-
|
32
|
-
@columns[name.to_sym] = {
|
33
|
-
name: name,
|
34
|
-
sort_sql: sort_sql || sql,
|
35
|
-
filter_sql: filter_sql || sql,
|
36
|
-
output: block,
|
37
|
-
table_column: table_column
|
38
|
-
}
|
39
57
|
end
|
40
58
|
|
41
59
|
def association(assoc, name, sort_sql: nil, filter_sql: nil, sql: nil, table_column_options: {}, &block)
|
42
|
-
@assocs ||= HashWithIndifferentAccess.new
|
43
|
-
@assocs[assoc.to_sym] ||= {}
|
44
60
|
@table_columns ||= []
|
45
|
-
|
61
|
+
assoc_klass = main_class.reflect_on_association(assoc.to_sym)
|
62
|
+
t_name = assoc_klass.try(:table_name)
|
63
|
+
table_column = Tabulatr::Renderer::Association.from(
|
64
|
+
table_column_options.merge(name: name, table_name: assoc,
|
65
|
+
klass: assoc_klass.try(:klass),
|
66
|
+
sort_sql: sort_sql || sql || "#{t_name}.#{name}",
|
67
|
+
filter_sql: filter_sql || sql || "#{t_name}.#{name}",
|
68
|
+
output: block_given? ? block : ->(record){record.send(assoc).try(name)}))
|
46
69
|
@table_columns << table_column
|
47
|
-
|
48
|
-
@assocs[assoc.to_sym][name.to_sym] = {
|
49
|
-
name: name,
|
50
|
-
sort_sql: sort_sql || sql,
|
51
|
-
filter_sql: filter_sql || sql,
|
52
|
-
output: block,
|
53
|
-
table_column: table_column
|
54
|
-
}
|
55
70
|
end
|
56
71
|
|
57
72
|
def search(*args, &block)
|
@@ -29,13 +29,15 @@ module Tabulatr::Data::Filtering
|
|
29
29
|
if @search.is_a? Array
|
30
30
|
query = query.strip.gsub(/['*%\s]+/, '%')
|
31
31
|
a = @search.map do |name|
|
32
|
-
|
32
|
+
column = table_columns.find{|c| c.name == name}
|
33
|
+
nn = column ? column.filter_sql : name
|
34
|
+
# nn = build_column_name name, use_for: :filter
|
33
35
|
"(#{nn} #{like} '%#{query}%')"
|
34
36
|
end
|
35
37
|
a = a.join(' OR ')
|
36
38
|
@relation = @relation.where(a)
|
37
39
|
else # search is a proc
|
38
|
-
|
40
|
+
execute_provided_search_block!(query)
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -46,8 +48,10 @@ module Tabulatr::Data::Filtering
|
|
46
48
|
filter_params.each do |filter|
|
47
49
|
name, value = filter
|
48
50
|
next unless value.present?
|
49
|
-
|
50
|
-
|
51
|
+
|
52
|
+
table_name, method_name = name.split(':').map(&:to_sym)
|
53
|
+
column = table_columns.find{|c| c.table_name == table_name && c.name == method_name}
|
54
|
+
apply_condition(column, value)
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
@@ -56,16 +60,16 @@ module Tabulatr::Data::Filtering
|
|
56
60
|
name, value = assoc_filter
|
57
61
|
assoc, att = name.split(".").map(&:to_sym)
|
58
62
|
table_name = table_name_for_association(assoc)
|
59
|
-
|
60
|
-
apply_condition(
|
63
|
+
column = table_columns.find{|c| c.table_name = table_name && name == name}
|
64
|
+
apply_condition(column, value)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
64
68
|
def apply_condition(n,v)
|
65
69
|
if ['true', 'false'].include?(v)
|
66
|
-
@relation = @relation.where(:"#{n}" => Tabulatr::Utility.string_to_boolean(v))
|
70
|
+
@relation = @relation.where(:"#{n.filter_sql}" => Tabulatr::Utility.string_to_boolean(v))
|
67
71
|
elsif v.is_a?(String)
|
68
|
-
apply_string_condition("#{n} = ?", v)
|
72
|
+
apply_string_condition("#{n.filter_sql} = ?", v)
|
69
73
|
elsif v.is_a?(Hash)
|
70
74
|
apply_hash_condition(n, v)
|
71
75
|
else
|
@@ -100,8 +104,8 @@ module Tabulatr::Data::Filtering
|
|
100
104
|
since = Date.parse(cond[:from]) if cond[:from].present?
|
101
105
|
to = Date.parse(cond[:to]) if cond[:to].present?
|
102
106
|
end
|
103
|
-
@relation = @relation.where("#{n} >= ?", since) if since.present?
|
104
|
-
@relation = @relation.where("#{n} <= ?", to) if to.present?
|
107
|
+
@relation = @relation.where("#{n.filter_sql} >= ?", since) if since.present?
|
108
|
+
@relation = @relation.where("#{n.filter_sql} <= ?", to) if to.present?
|
105
109
|
end
|
106
110
|
|
107
111
|
def apply_string_condition(replacement_string, value)
|
@@ -110,10 +114,34 @@ module Tabulatr::Data::Filtering
|
|
110
114
|
|
111
115
|
def apply_hash_condition(column_name, hash)
|
112
116
|
like ||= Tabulatr::Utility.like_statement
|
113
|
-
apply_string_condition("#{column_name} #{like} ?", "%#{hash[:like]}%") if hash[:like].present?
|
117
|
+
apply_string_condition("#{column_name.filter_sql} #{like} ?", "%#{hash[:like]}%") if hash[:like].present?
|
114
118
|
apply_date_condition(column_name, hash[:date])
|
115
|
-
apply_string_condition("#{column_name} >= ?", "#{hash[:from]}")
|
116
|
-
apply_string_condition("#{column_name} <= ?", "#{hash[:to]}")
|
119
|
+
apply_string_condition("#{column_name.filter_sql} >= ?", "#{hash[:from]}")
|
120
|
+
apply_string_condition("#{column_name.filter_sql} <= ?", "#{hash[:to]}")
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def execute_provided_search_block!(query)
|
126
|
+
if @search.arity == 1
|
127
|
+
search_result = @search.(query)
|
128
|
+
elsif @search.arity == 2
|
129
|
+
search_result = @search.(query, @relation)
|
130
|
+
else
|
131
|
+
raise 'Search block needs either `query` or both `query` and `relation` block variables'
|
132
|
+
end
|
133
|
+
handle_search_result(search_result)
|
134
|
+
end
|
135
|
+
|
136
|
+
def handle_search_result(search_result)
|
137
|
+
return if search_result.nil?
|
138
|
+
if search_result.is_a?(ActiveRecord::Relation)
|
139
|
+
@relation = search_result
|
140
|
+
elsif search_result.is_a?(String) || search_result.is_a?(Hash) || search_result.is_a?(Array)
|
141
|
+
@relation = @relation.where(search_result)
|
142
|
+
else
|
143
|
+
Tabulatr::UnexpectedSearchResultError.raise_error(search_result.class)
|
144
|
+
end
|
117
145
|
end
|
118
146
|
|
119
147
|
end
|
@@ -28,31 +28,18 @@ module Tabulatr::Data::Formatting
|
|
28
28
|
return @relation.map do |record|
|
29
29
|
view.record = record
|
30
30
|
h = HashWithIndifferentAccess.new
|
31
|
-
|
32
|
-
h[
|
33
|
-
|
34
|
-
|
35
|
-
h[table_name] ||= {}
|
36
|
-
columns.each do |name, opts|
|
37
|
-
h[table_name][name] = format_association(record, table_name, name, opts, view)
|
38
|
-
end
|
39
|
-
end # @assocs each
|
31
|
+
table_columns.each do |tc|
|
32
|
+
h[tc.table_name] ||= HashWithIndifferentAccess.new
|
33
|
+
h[tc.table_name][tc.name] = format_column(record, tc.output, view)
|
34
|
+
end
|
40
35
|
h[:_row_config] = format_row(view, @row)
|
36
|
+
h[:id] = record.id
|
41
37
|
h
|
42
38
|
end # @relation map
|
43
39
|
end # apply_formats
|
44
40
|
|
45
|
-
def format_column(record,
|
46
|
-
|
47
|
-
view.instance_exec(record, &opts[:output])
|
48
|
-
else
|
49
|
-
opts[:table_column].value_for(record, view)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def format_association(record, table_name, name, opts, view)
|
54
|
-
return view.instance_exec(record, &opts[:output]) if opts[:output]
|
55
|
-
opts[:table_column].value_for(record, view)
|
41
|
+
def format_column(record, output, view)
|
42
|
+
view.instance_exec(record, &output) if output.present?
|
56
43
|
end
|
57
44
|
|
58
45
|
def format_row(view, row)
|
@@ -23,7 +23,7 @@
|
|
23
23
|
|
24
24
|
module Tabulatr::Data::Pagination
|
25
25
|
|
26
|
-
def apply_pagination(offset: 0, pagesize: nil
|
26
|
+
def apply_pagination(offset: 0, pagesize: nil)
|
27
27
|
@relation = @relation.limit(pagesize).offset(offset)
|
28
28
|
end
|
29
29
|
|
@@ -33,7 +33,6 @@ module Tabulatr::Data::Pagination
|
|
33
33
|
pagesize, page = pagesize.to_i, page.to_i
|
34
34
|
|
35
35
|
pages = (count/pagesize.to_f).ceil
|
36
|
-
|
37
36
|
{
|
38
37
|
offset: [0,((page-1)*pagesize).to_i].max,
|
39
38
|
pagesize: pagesize,
|
data/lib/tabulatr/data/proxy.rb
CHANGED
@@ -27,6 +27,7 @@ class Data::Proxy < ActionView::Base
|
|
27
27
|
|
28
28
|
def initialize(record=nil, locals: {})
|
29
29
|
self.class._init
|
30
|
+
Rails.application.routes.mounted_helpers.instance_methods.each{|f| self.send(f).instance_variable_set('@scope', self)}
|
30
31
|
@record = record
|
31
32
|
locals.each do |nam, val|
|
32
33
|
raise "cowardly refusing to override `#{nam}'" if respond_to? nam
|
@@ -40,6 +41,7 @@ class Data::Proxy < ActionView::Base
|
|
40
41
|
include ActionView::Helpers
|
41
42
|
include Rails.application.helpers
|
42
43
|
include Rails.application.routes.url_helpers
|
44
|
+
include Rails.application.routes.mounted_helpers
|
43
45
|
end
|
44
46
|
|
45
47
|
end
|
@@ -23,26 +23,37 @@
|
|
23
23
|
|
24
24
|
module Tabulatr::Data::Sorting
|
25
25
|
|
26
|
-
def apply_sorting(sortparam
|
26
|
+
def apply_sorting(sortparam)
|
27
27
|
if sortparam.present?
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
assoc_name = nil
|
32
|
-
if klass == @cname
|
33
|
-
table_name = @base.table_name
|
28
|
+
clname, orientation = sortparam.split(' ')
|
29
|
+
if clname[':']
|
30
|
+
splitted = clname.split(':')
|
34
31
|
else
|
35
|
-
|
36
|
-
table_name = @base.reflect_on_association(klass.to_sym).try(:table_name)
|
32
|
+
splitted = clname.split('.')
|
37
33
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
if splitted.count == 2
|
35
|
+
assoc_name = splitted[0].to_sym
|
36
|
+
name = splitted[1].to_sym
|
37
|
+
column = table_columns.find{|c| c.table_name == assoc_name && c.name == name}
|
38
|
+
else
|
39
|
+
name = splitted[0].to_sym
|
40
|
+
column = table_columns.find{|c| c.name == name}
|
41
|
+
end
|
42
|
+
sort_by(column, orientation)
|
41
43
|
else
|
42
|
-
@relation = @relation.
|
44
|
+
@relation = @relation.reorder("#{@table_name}.#{@base.primary_key} desc")
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
48
|
+
def sort_by(column, orientation)
|
49
|
+
sort_sql = column.sort_sql
|
50
|
+
if sort_sql.respond_to? :call
|
51
|
+
@relation = sort_sql.call(@relation, orientation, "#{@table_name}.#{@base.primary_key}", @base)
|
52
|
+
else
|
53
|
+
@relation = @relation.reorder("#{sort_sql} #{orientation}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
46
57
|
end
|
47
58
|
|
48
59
|
Tabulatr::Data.send :include, Tabulatr::Data::Sorting
|
data/lib/tabulatr/engine.rb
CHANGED
@@ -5,7 +5,7 @@ en:
|
|
5
5
|
batch_actions: 'Batch actions'
|
6
6
|
count: 'Showing: %{current} of total %{total}. %{per_page} items per page.'
|
7
7
|
apply_filters: 'Apply'
|
8
|
-
search: 'Search'
|
8
|
+
search: 'Search...'
|
9
9
|
date_filter:
|
10
10
|
none: ''
|
11
11
|
today: "Today"
|
@@ -27,7 +27,7 @@ de:
|
|
27
27
|
batch_actions: 'Batch-Aktionen'
|
28
28
|
count: 'Zeige %{current} von insgesamt %{total}. %{per_page} pro Seite.'
|
29
29
|
apply_filters: 'Anwenden'
|
30
|
-
search: 'Suche'
|
30
|
+
search: 'Suche...'
|
31
31
|
date_filter:
|
32
32
|
none: ''
|
33
33
|
today: "Heute"
|
@@ -62,34 +62,32 @@ module Tabulatr::JsonBuilder
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.insert_attribute_in_hash at, f, r={}
|
65
|
+
action = at[:action].to_sym
|
66
|
+
relation = at[:relation].try(:to_sym)
|
65
67
|
if at.has_key? :relation
|
66
|
-
|
67
|
-
action
|
68
|
-
|
69
|
-
# if at[:action].to_sym == :count
|
70
|
-
# r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).count
|
71
|
-
# else
|
72
|
-
# r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).map(&at[:action].to_sym).join(', ')
|
73
|
-
# end
|
74
|
-
# else
|
75
|
-
# r["#{at[:relation]}:#{at[:action]}"] = f.try(at[:relation]).try(at[:action])
|
76
|
-
# end
|
77
|
-
begin
|
78
|
-
raise Tabulatr::RequestDataNotIncludedError.raise_error(rel, f) if !f.has_key?(rel)
|
79
|
-
raise Tabulatr::RequestDataNotIncludedError.raise_error(action, rel) if !f[rel].has_key?(action) && action != :id
|
80
|
-
r["#{at[:relation]}:#{at[:action]}"] = f[rel][action]
|
81
|
-
rescue TypeError, NoMethodError => e
|
82
|
-
Tabulatr::RequestDataNotIncludedError.raise_error(at[:action], at[:relation])
|
83
|
-
end
|
68
|
+
check_if_attribute_is_in_hash(f, relation)
|
69
|
+
check_if_attribute_is_in_hash(f[relation], action) if action != :id
|
70
|
+
set_value_at_key(r, f[relation][action], "#{at[:relation]}:#{at[:action]}")
|
84
71
|
else
|
85
|
-
|
86
|
-
|
87
|
-
raise Tabulatr::RequestDataNotIncludedError.raise_error(action, f) if !f.has_key?(action) && [:checkbox, :id].exclude?(action)
|
88
|
-
r[at[:action]] = f[action]
|
89
|
-
rescue TypeError, NoMethodError => e
|
90
|
-
raise Tabulatr::RequestDataNotIncludedError.raise_error(action, f)
|
91
|
-
end
|
72
|
+
check_if_attribute_is_in_hash(f, action) if [:checkbox, :id].exclude?(action)
|
73
|
+
set_value_at_key(r, f[action], at[:action])
|
92
74
|
end
|
93
75
|
r
|
94
76
|
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def self.check_if_attribute_is_in_hash hash, key
|
81
|
+
if !hash.has_key?(key)
|
82
|
+
raise Tabulatr::RequestDataNotIncludedError.raise_error(key, hash)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.set_value_at_key hash, value, key
|
87
|
+
begin
|
88
|
+
hash[key] = value
|
89
|
+
rescue TypeError, NoMethodError => e
|
90
|
+
raise Tabulatr::RequestDataNotIncludedError.raise_error(key, value)
|
91
|
+
end
|
92
|
+
end
|
95
93
|
end
|
@@ -22,6 +22,10 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
class ActionController::Base
|
25
|
+
before_filter do
|
26
|
+
@_tabulatr_table_index = 0
|
27
|
+
end
|
28
|
+
|
25
29
|
def tabulatr_for(relation, tabulatr_data_class: nil, serializer: nil, render_action: nil, locals: {}, &block)
|
26
30
|
klass = relation.respond_to?(:klass) ? relation.klass : relation
|
27
31
|
respond_to do |format|
|
@@ -23,8 +23,9 @@
|
|
23
23
|
|
24
24
|
class ActionView::Base
|
25
25
|
# render the table in a view
|
26
|
-
def table_for(klass, columns: [], **opts, &block)
|
27
|
-
|
26
|
+
def table_for(klass, columns: [], tabulatr_data_class: nil, **opts, &block)
|
27
|
+
@_tabulatr_table_index += 1
|
28
|
+
Tabulatr::Renderer.build_table(klass, self, opts, columns, tabulatr_data_class, &block)
|
28
29
|
end
|
29
30
|
|
30
31
|
def static_table_for(records, opts={}, &block)
|
@@ -22,8 +22,10 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
class Tabulatr::Renderer::Checkbox < Tabulatr::Renderer::Column
|
25
|
+
include ActionView::Helpers::FormTagHelper
|
26
|
+
|
25
27
|
def human_name
|
26
|
-
|
28
|
+
check_box_tag('mark_all', '1', false, class: 'tabulatr_mark_all').html_safe
|
27
29
|
end
|
28
30
|
|
29
31
|
def coltype() 'checkbox' end
|
@@ -26,7 +26,8 @@ class Tabulatr::Renderer::Column
|
|
26
26
|
|
27
27
|
attr_accessor *%i{name header width align valign wrap type th_html filter_html
|
28
28
|
filter filter_width range_filter_symbol
|
29
|
-
sortable table_name block klass format map classes cell_style header_style
|
29
|
+
sortable table_name block klass format map classes cell_style header_style
|
30
|
+
sort_sql filter_sql output}
|
30
31
|
|
31
32
|
def self.from(
|
32
33
|
name: nil,
|
@@ -46,6 +47,9 @@ class Tabulatr::Renderer::Column
|
|
46
47
|
klass: nil,
|
47
48
|
cell_style: {},
|
48
49
|
header_style: {},
|
50
|
+
sort_sql: nil,
|
51
|
+
filter_sql: nil,
|
52
|
+
output: nil,
|
49
53
|
&block)
|
50
54
|
b = block_given? ? block : nil
|
51
55
|
self.new(
|
@@ -66,10 +70,41 @@ class Tabulatr::Renderer::Column
|
|
66
70
|
klass: klass,
|
67
71
|
block: b,
|
68
72
|
cell_style: cell_style,
|
69
|
-
header_style: header_style
|
73
|
+
header_style: header_style,
|
74
|
+
sort_sql: sort_sql,
|
75
|
+
filter_sql: filter_sql,
|
76
|
+
output: output
|
70
77
|
).apply_styles!
|
71
78
|
end
|
72
79
|
|
80
|
+
def update_options(hash = {}, &block)
|
81
|
+
self.header = hash[:header] || self.header
|
82
|
+
self.classes = hash[:classes] || self.classes
|
83
|
+
self.width = hash[:width] || self.width
|
84
|
+
self.align = hash[:align] || self.align
|
85
|
+
self.valign = hash[:valign] || self.valign
|
86
|
+
self.wrap = hash[:wrap] || self.wrap
|
87
|
+
self.th_html = hash[:th_html] || self.th_html
|
88
|
+
self.filter_html = hash[:filter_html] || self.filter_html
|
89
|
+
self.filter = hash[:filter] || self.filter
|
90
|
+
self.sortable = hash[:sortable] || self.sortable
|
91
|
+
self.format = hash[:format] || self.format
|
92
|
+
self.map = hash[:map] || self.map
|
93
|
+
self.th_html = hash[:th_html] || self.th_html
|
94
|
+
self.output = block if block_given?
|
95
|
+
self.filter_sql = hash[:filter_sql] || self.filter_sql
|
96
|
+
self.sort_sql = hash[:sort_sql] || self.sort_sql
|
97
|
+
if self.cell_style == ''
|
98
|
+
self.cell_style = {}
|
99
|
+
end
|
100
|
+
self.cell_style = hash[:cell_style] || self.cell_style
|
101
|
+
if self.header_style == ''
|
102
|
+
self.header_style = {}
|
103
|
+
end
|
104
|
+
self.header_style = hash[:header_style] || self.header_style
|
105
|
+
self.apply_styles!
|
106
|
+
end
|
107
|
+
|
73
108
|
def klassname() @_klassname ||= @klass.name.underscore end
|
74
109
|
def human_name() header || klass.human_attribute_name(name) end
|
75
110
|
def sort_param() "#{klassname}_sort" end
|
@@ -83,11 +118,19 @@ class Tabulatr::Renderer::Column
|
|
83
118
|
|
84
119
|
def apply_styles!
|
85
120
|
# raise cell_style.inspect
|
86
|
-
self.cell_style = style_options.merge(self.cell_style)
|
87
|
-
self.header_style = style_options.merge(self.header_style)
|
121
|
+
self.cell_style = style_options.merge(self.cell_style)
|
122
|
+
self.header_style = style_options.merge(self.header_style)
|
88
123
|
self
|
89
124
|
end
|
90
125
|
|
126
|
+
def html_cell_style
|
127
|
+
cell_style.map{|e| e.join(':')}.join(';')
|
128
|
+
end
|
129
|
+
|
130
|
+
def html_header_style
|
131
|
+
header_style.map{|e| e.join(':')}.join(';')
|
132
|
+
end
|
133
|
+
|
91
134
|
def style_options
|
92
135
|
default_style_attributes = {
|
93
136
|
:'text-align' => align,
|
@@ -106,7 +149,6 @@ class Tabulatr::Renderer::Column
|
|
106
149
|
return r
|
107
150
|
end
|
108
151
|
val = principal_value(record) or return ''
|
109
|
-
|
110
152
|
if format.present? && val.respond_to?(:to_ary)
|
111
153
|
val.map do |v|
|
112
154
|
case format
|