tabulatr2 0.9.4 → 0.9.6
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.
- 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
|