tabulatr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +106 -0
- data/LICENSE +23 -0
- data/README.textile +284 -0
- data/Rakefile +11 -0
- data/assets/simple_table.png +0 -0
- data/assets/tabulatr.css +107 -0
- data/lib/initializers/action_view.rb +31 -0
- data/lib/initializers/active_record.rb +32 -0
- data/lib/initializers/mark_as_localizable.rb +43 -0
- data/lib/initializers/mongoid.rb +34 -0
- data/lib/tabulatr/tabulatr/batch_actions.rb +52 -0
- data/lib/tabulatr/tabulatr/check_controls.rb +43 -0
- data/lib/tabulatr/tabulatr/data_cell.rb +118 -0
- data/lib/tabulatr/tabulatr/filter_cell.rb +130 -0
- data/lib/tabulatr/tabulatr/finder/find_for_active_record_table.rb +162 -0
- data/lib/tabulatr/tabulatr/finder/find_for_mongoid_table.rb +116 -0
- data/lib/tabulatr/tabulatr/finder.rb +82 -0
- data/lib/tabulatr/tabulatr/formattr.rb +51 -0
- data/lib/tabulatr/tabulatr/header_cell.rb +94 -0
- data/lib/tabulatr/tabulatr/paginator.rb +88 -0
- data/lib/tabulatr/tabulatr/row_builder.rb +115 -0
- data/lib/tabulatr/tabulatr/settings.rb +221 -0
- data/lib/tabulatr/tabulatr.rb +238 -0
- data/lib/tabulatr.rb +34 -0
- data/tabulatr.gemspec +26 -0
- metadata +143 -0
@@ -0,0 +1,82 @@
|
|
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_active_record_table')
|
28
|
+
require File.join(File.dirname(__FILE__), 'finder', 'find_for_mongoid_table')
|
29
|
+
|
30
|
+
# compress the list of ids as good as I could imagine ;)
|
31
|
+
# uses fancy base twisting
|
32
|
+
def self.compress_id_list(list)
|
33
|
+
IdStuffer.stuff(list)
|
34
|
+
end
|
35
|
+
|
36
|
+
# inverse of compress_id_list
|
37
|
+
def self.uncompress_id_list(str)
|
38
|
+
IdStuffer.unstuff(str).map &:to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
class Invoker
|
42
|
+
def initialize(batch_action, ids)
|
43
|
+
@batch_action = batch_action.to_sym
|
44
|
+
@ids = ids
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing(name, *args, &block)
|
48
|
+
if @batch_action == name
|
49
|
+
yield(@ids, args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def self.class_to_param(klaz)
|
57
|
+
klaz.to_s.downcase.gsub("/","_")
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.condition_from(n,v,c)
|
61
|
+
raise "SECURITY violation, field name is '#{n}'" unless /^[\d\w]+(\.[\d\w]+)?$/.match n
|
62
|
+
@like ||= Tabulatr.sql_options[:like]
|
63
|
+
nc = c
|
64
|
+
if v.is_a?(String)
|
65
|
+
if v.present?
|
66
|
+
nc = [c[0] << " AND (#{n} = ?) ", c[1] << v]
|
67
|
+
end
|
68
|
+
elsif v.is_a?(Hash)
|
69
|
+
if v[:like]
|
70
|
+
if v[:like].present?
|
71
|
+
nc = [c[0] << " AND (#{n} #{@like} ?) ", c[1] << "%#{v[:like]}%"]
|
72
|
+
end
|
73
|
+
else
|
74
|
+
nc = [c[0] << " AND (#{n} >= ?) ", c[1] << "#{v[:from]}"] if v[:from].present?
|
75
|
+
nc = [nc[0] << " AND (#{n} <= ?) ", nc[1] << "#{v[:to]}"] if v[:to].present?
|
76
|
+
end
|
77
|
+
else
|
78
|
+
raise "Wrong filter type: #{v.class}"
|
79
|
+
end
|
80
|
+
nc
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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
|
+
|
27
|
+
def self.format(nam, val)
|
28
|
+
nam = nam.to_sym
|
29
|
+
if ALLOWED_METHODS.member?(nam)
|
30
|
+
self.send nam, val
|
31
|
+
else
|
32
|
+
"[Requested unautorized format '#{nam}' for '#{val}'.]"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.euro(x)
|
37
|
+
("%.2f €" % x).gsub(".", ",")
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.dollar(x)
|
41
|
+
"$ %.2f" % x
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.percent(x)
|
45
|
+
("%.2f&thinspace;%%" % 100.0*x).gsub(".", ",")
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.lamp(x)
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,94 @@
|
|
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
|
+
bid = "#{@classname}#{@table_form_options[:sort_postfix]}"
|
38
|
+
opts = normalize_column_options opts
|
39
|
+
make_tag(:th, opts[:th_html]) do
|
40
|
+
concat(t(opts[:header] || name.to_s.capitalize), :escape_html)
|
41
|
+
if opts[:sortable] and @table_options[:sortable]
|
42
|
+
if @sorting and @sorting[:by].to_s == name.to_s
|
43
|
+
pname = "#{sortparam}[_resort][#{name}][#{@sorting[:direction] == 'asc' ? 'desc' : 'asc'}]"
|
44
|
+
bid = "#{bid}_#{name}_#{@sorting[:direction] == 'asc' ? 'desc' : 'asc'}"
|
45
|
+
psrc = File.join(@table_options[:image_path_prefix], @table_options[@sorting[:direction] == 'desc' ?
|
46
|
+
:sort_down_button : :sort_up_button])
|
47
|
+
make_tag(:input, :type => :hidden,
|
48
|
+
:name => "#{sortparam}[#{name}][#{@sorting[:direction]}]",
|
49
|
+
:value => "#{@sorting[:direction]}")
|
50
|
+
else
|
51
|
+
pname = "#{sortparam}[_resort][#{name}][desc]"
|
52
|
+
bid = "#{bid}_#{name}_desc"
|
53
|
+
psrc = File.join(@table_options[:image_path_prefix], @table_options[:sort_down_button_inactive])
|
54
|
+
end
|
55
|
+
make_tag(:input, :type => 'image',
|
56
|
+
:id => bid,
|
57
|
+
:src => psrc,
|
58
|
+
:name => pname)
|
59
|
+
end
|
60
|
+
end # </th>
|
61
|
+
end
|
62
|
+
|
63
|
+
# the method used to actually define the headers of the columns,
|
64
|
+
# taking the name of the attribute and a hash of options.
|
65
|
+
#
|
66
|
+
# The following options are evaluated here:
|
67
|
+
# <tt>:th_html</tt>:: a hash with html-attributes added to the <th>s created
|
68
|
+
# <tt>:header</tt>:: if present, the value will be output in the header cell,
|
69
|
+
# otherwise, the capitalized name is used
|
70
|
+
def header_association(relation, name, opts={}, &block)
|
71
|
+
raise "Not in header mode!" if @row_mode != :header
|
72
|
+
opts = normalize_column_options opts
|
73
|
+
if opts[:sortable] and @table_options[:sortable]
|
74
|
+
# change classes accordingly
|
75
|
+
end
|
76
|
+
make_tag(:th, opts[:th_html]) do
|
77
|
+
concat(t(opts[:header] || "#{relation.to_s.capitalize} #{name.to_s.capitalize}"), :escape_html)
|
78
|
+
end # </th>
|
79
|
+
end
|
80
|
+
|
81
|
+
def header_checkbox(opts={}, &block)
|
82
|
+
raise "Whatever that's for!" if block_given?
|
83
|
+
make_tag(:th, opts[:th_html]) do
|
84
|
+
concat(t(opts[:header] || ""), :escape_html)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def header_action(opts={}, &block)
|
89
|
+
make_tag(:th, opts[:th_html]) do
|
90
|
+
concat(t(opts[:header] || ""), :escape_html)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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
|
+
pagination_name = "#{@classname}#{TABLE_FORM_OPTIONS[:pagination_postfix]}"
|
30
|
+
pparams = @records.send(FINDER_INJECT_OPTIONS[:pagination])
|
31
|
+
page = pparams[:page].to_i
|
32
|
+
pages = pparams[:pages].to_i
|
33
|
+
pagesize = pparams[:pagesize].to_i
|
34
|
+
pagesizes = pparams[:pagesizes].map &:to_i
|
35
|
+
# render the 'wrapping' div
|
36
|
+
make_tag(:div, :class => @table_options[:paginator_div_class]) do
|
37
|
+
# << Page Left
|
38
|
+
if page > 1
|
39
|
+
make_tag(:input, :type => 'image',
|
40
|
+
:src => File.join(@table_options[:image_path_prefix], @table_options[:pager_left_button]),
|
41
|
+
:class => @table_options[:page_left_class],
|
42
|
+
:id => "#{pagination_name}_page_left",
|
43
|
+
:name => "#{pagination_name}[page_left]")
|
44
|
+
else
|
45
|
+
make_tag(:img,
|
46
|
+
:src => File.join(@table_options[:image_path_prefix], @table_options[:pager_left_button_inactive]),
|
47
|
+
:class => @table_options[:page_left_class])
|
48
|
+
end # page > 1
|
49
|
+
# current page number
|
50
|
+
concat(make_tag(:input,
|
51
|
+
:type => :hidden,
|
52
|
+
:name => "#{pagination_name}[current_page]",
|
53
|
+
:value => page))
|
54
|
+
concat(make_tag(:input,
|
55
|
+
:type => :text,
|
56
|
+
:size => pages.to_s.length,
|
57
|
+
:name => "#{pagination_name}[page]",
|
58
|
+
:value => page))
|
59
|
+
concat("/#{pages}")
|
60
|
+
# >> Page Right
|
61
|
+
if page < pages
|
62
|
+
make_tag(:input, :type => 'image',
|
63
|
+
:src => File.join(@table_options[:image_path_prefix], @table_options[:pager_right_button]),
|
64
|
+
:class => @table_options[:page_right_class],
|
65
|
+
:id => "#{pagination_name}_page_right",
|
66
|
+
:name => "#{pagination_name}[page_right]")
|
67
|
+
else
|
68
|
+
make_tag(:img, :src => File.join(@table_options[:image_path_prefix], @table_options[:pager_right_button_inactive]),
|
69
|
+
:class => @table_options[:page_right_class])
|
70
|
+
end # page < pages
|
71
|
+
if pagesizes.length > 1
|
72
|
+
make_tag(:select, :name => "#{pagination_name}[pagesize]", :class => @table_options[:pagesize_select_class]) do
|
73
|
+
pagesizes.each do |n|
|
74
|
+
make_tag(:option, (n.to_i==pagesize ? {:selected => :selected} : {}).merge(:value => n)) do
|
75
|
+
concat(n.to_s)
|
76
|
+
end # </option>
|
77
|
+
end # each
|
78
|
+
end # </select>
|
79
|
+
else # just one pagesize
|
80
|
+
concat(make_tag(:input,
|
81
|
+
:type => :hidden,
|
82
|
+
:name => "#{pagination_name}[pagesize]",
|
83
|
+
:value => pagesizes.first))
|
84
|
+
end
|
85
|
+
end # </div>
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,115 @@
|
|
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 as a row builder
|
25
|
+
# In a seperate class call only for clearity
|
26
|
+
|
27
|
+
class Tabulatr
|
28
|
+
|
29
|
+
# called inside the build_table block, branches into data, header,
|
30
|
+
# or filter building methods depending on the current mode
|
31
|
+
def column(name, opts={}, &block)
|
32
|
+
#puts "column: '#{name}'"
|
33
|
+
case @row_mode
|
34
|
+
when :data then data_column(name, opts, &block)
|
35
|
+
when :header then header_column(name, opts, &block)
|
36
|
+
when :filter then filter_column(name, opts, &block)
|
37
|
+
else raise "Wrong row mode '#{@row_mode}'"
|
38
|
+
end # case
|
39
|
+
end
|
40
|
+
|
41
|
+
# called inside the build_table block, branches into data, header,
|
42
|
+
# or filter building methods depending on the current mode
|
43
|
+
def association(relation, name, opts={}, &block)
|
44
|
+
#puts "assoc: '#{relation}.#{name}'"
|
45
|
+
case @row_mode
|
46
|
+
when :data then data_association(relation, name, opts, &block)
|
47
|
+
when :header then header_association(relation, name, opts, &block)
|
48
|
+
when :filter then filter_association(relation, name, opts, &block)
|
49
|
+
else raise "Wrong row mode '#{@row_mode}'"
|
50
|
+
end # case
|
51
|
+
end
|
52
|
+
|
53
|
+
# called inside the build_table block, branches into data, header,
|
54
|
+
# or filter building methods depending on the current mode
|
55
|
+
def checkbox(opts={}, &block)
|
56
|
+
#puts "column: '#{name}'"
|
57
|
+
case @row_mode
|
58
|
+
when :data then data_checkbox(opts, &block)
|
59
|
+
when :header then header_checkbox(opts, &block)
|
60
|
+
when :filter then filter_checkbox(opts, &block)
|
61
|
+
else raise "Wrong row mode '#{@row_mode}'"
|
62
|
+
end # case
|
63
|
+
end
|
64
|
+
|
65
|
+
def action(opts={}, &block)
|
66
|
+
#puts "column: '#{name}'"
|
67
|
+
case @row_mode
|
68
|
+
when :data then data_action(opts, &block)
|
69
|
+
when :header then header_action(opts, &block)
|
70
|
+
when :filter then filter_action(opts, &block)
|
71
|
+
else raise "Wrong row mode '#{@row_mode}'"
|
72
|
+
end # case
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
# returns self, sets record and row_mode as required for a
|
77
|
+
# data row
|
78
|
+
def data_row_builder(record)
|
79
|
+
@record = record
|
80
|
+
@row_mode = :data
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
# returns self, sets record to nil and row_mode as required for a
|
85
|
+
# header row
|
86
|
+
def header_row_builder
|
87
|
+
@record = nil
|
88
|
+
@row_mode = :header
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# returns self, sets record to nil and row_mode as required for a
|
93
|
+
# filter row
|
94
|
+
def filter_row_builder
|
95
|
+
@record = nil
|
96
|
+
@row_mode = :filter
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
# some preprocessing of the options
|
101
|
+
def normalize_column_options(opts)
|
102
|
+
opts = Tabulatr::COLUMN_OPTIONS.merge(opts)
|
103
|
+
{:width => 'width', :align => 'text-align', :valign => 'vertical-align'}.each do |key,css|
|
104
|
+
if opts[key]
|
105
|
+
[:th_html, :filter_html, :td_html].each do |set|
|
106
|
+
opts[set] ||= {}
|
107
|
+
opts[set][:style] = (opts[set][:style] ? opts[set][:style] << "; " : "") << "#{css}: #{opts[key]}"
|
108
|
+
end # each
|
109
|
+
end # if
|
110
|
+
end # each
|
111
|
+
# more to come!
|
112
|
+
opts
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,221 @@
|
|
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
|
+
require 'whiny_hash'
|
25
|
+
|
26
|
+
class Tabulatr
|
27
|
+
|
28
|
+
# Hash keeping the defaults for the table options, may be overriden in the
|
29
|
+
# table_for call
|
30
|
+
TABLE_OPTIONS = WhinyHash.new({ # WhinyHash.new({
|
31
|
+
remote: false, # add data-remote="true" to form
|
32
|
+
|
33
|
+
form_class: 'tabulatr_form', # class of the overall form
|
34
|
+
table_class: 'tabulatr_table', # class for the actual data table
|
35
|
+
sortable_class: 'sortable', # class for the header of a sortable column
|
36
|
+
sorting_asc_class: 'sorting-asc', # class for the currently asc sorting column
|
37
|
+
sorting_desc_class: 'sorting-desc', # class for the currently desc sorting column
|
38
|
+
page_left_class: 'page-left', # class for the page left button
|
39
|
+
page_right_class: 'page-right', # class for the page right button
|
40
|
+
page_no_class: 'page-no', # class for the page no <input>
|
41
|
+
control_div_class_before: 'table-controls', # class of the upper div containing the paging and batch action controls
|
42
|
+
control_div_class_after: 'table-controls', # class of the lower div containing the paging and batch action controls
|
43
|
+
paginator_div_class: 'paginator', # class of the div containing the paging controls
|
44
|
+
batch_actions_div_class: 'batch-actions', # class of the div containing the batch action controls
|
45
|
+
select_controls_div_class: 'check-controls', # class of the div containing the check controls
|
46
|
+
submit_class: 'submit-table', # class of submit button
|
47
|
+
pagesize_select_class: 'pagesize_select', # class of the pagesize select element
|
48
|
+
select_all_class: 'select-btn', # class of the select all button
|
49
|
+
select_none_class: 'select-btn', # class of the select none button
|
50
|
+
select_visible_class: 'select-btn', # class of the select visible button
|
51
|
+
unselect_visible_class: 'select-btn', # class of the unselect visible button
|
52
|
+
select_filtered_class: 'select-btn', # class of the select filtered button
|
53
|
+
unselect_filtered_class: 'select-btn', # class of the unselect filteredbutton
|
54
|
+
info_text_class: 'info-text', # class of the info text div
|
55
|
+
|
56
|
+
batch_actions_label: 'Batch Action: ', # Text to show in front of the batch action select
|
57
|
+
batch_actions_type: :select, # :select or :button depending on the kind of input you want
|
58
|
+
batch_actions_class: 'batch-action-inputs', # class to apply on the batch action input elements
|
59
|
+
submit_label: 'Apply', # Text on the submit button
|
60
|
+
select_all_label: 'Select All', # Text on the select all button
|
61
|
+
select_none_label: 'Select None', # Text on the select none button
|
62
|
+
select_visible_label: 'Select visible', # Text on the select visible button
|
63
|
+
unselect_visible_label: 'Unselect visible', # Text on the unselect visible button
|
64
|
+
select_filtered_label: 'Select filtered', # Text on the select filtered button
|
65
|
+
unselect_filtered_label: 'Unselect filtered',# Text on the unselect filtered button
|
66
|
+
info_text: "Showing %1$d, total %2$d, selected %3$d, matching %4$d",
|
67
|
+
|
68
|
+
# which controls to be rendered above and below the tabel and in which order
|
69
|
+
before_table_controls: [:submit, :paginator, :batch_actions, :select_controls, :info_text],
|
70
|
+
after_table_controls: [],
|
71
|
+
|
72
|
+
# whih selecting controls to render in which order
|
73
|
+
select_controls: [:select_all, :select_none, :select_visible, :unselect_visible,
|
74
|
+
:select_filtered, :unselect_filtered],
|
75
|
+
|
76
|
+
|
77
|
+
image_path_prefix: '/images/tabulatr/',
|
78
|
+
pager_left_button: 'left.gif',
|
79
|
+
pager_left_button_inactive: 'left_off.gif',
|
80
|
+
pager_right_button: 'right.gif',
|
81
|
+
pager_right_button_inactive: 'right_off.gif',
|
82
|
+
sort_up_button: 'up.gif',
|
83
|
+
sort_up_button_inactive: 'up_off.gif',
|
84
|
+
sort_down_button: 'down.gif',
|
85
|
+
sort_down_button_inactive: 'down_off.gif',
|
86
|
+
|
87
|
+
make_form: true, # whether or not to wrap the whole table (incl. controls) in a form
|
88
|
+
table_html: false, # a hash with html attributes for the table
|
89
|
+
row_html: false, # a hash with html attributes for the normal trs
|
90
|
+
header_html: false, # a hash with html attributes for the header trs
|
91
|
+
filter_html: false, # a hash with html attributes for the filter trs
|
92
|
+
filter: true, # false for no filter row at all
|
93
|
+
paginate: true, # true to show paginator
|
94
|
+
sortable: true, # true to allow sorting (can be specified for every sortable column)
|
95
|
+
selectable: true, # true to render "select all", "select none" and the like
|
96
|
+
action: nil, # target action of the wrapping form if applicable
|
97
|
+
batch_actions: false, # name: value hash of batch action stuff
|
98
|
+
translate: false, # call t() for all 'labels' and stuff, possible values are true/:translate or :localize
|
99
|
+
row_classes: ['odd', 'even'] # class for the trs
|
100
|
+
})
|
101
|
+
|
102
|
+
# these settings are considered constant for the whole application, can not be overridden
|
103
|
+
# on a per-table basis.
|
104
|
+
# That's necessary to allow find_for_table to work properly
|
105
|
+
TABLE_FORM_OPTIONS = WhinyHash.new({
|
106
|
+
batch_action_name: 'batch_action', # name of the batch action param
|
107
|
+
sort_by_key: 'sort_by_key', # name of key which to search, format is 'id asc'
|
108
|
+
pagination_postfix: '_pagination', # name of the param w/ the pagination infos
|
109
|
+
filter_postfix: '_filter', # postfix for name of the filter in the params hash: xxx_filter
|
110
|
+
sort_postfix: '_sort', # postfix for name of the filter in the params hash: xxx_filter
|
111
|
+
checked_postfix: '_checked', # postfix for name of the checked in the params hash: xxx_filter
|
112
|
+
associations_filter: '__association', # name of the associations in the filter hash
|
113
|
+
method: 'post', # http method for that form if applicable
|
114
|
+
batch_postfix: '_batch', # postfix for name of the batch action select
|
115
|
+
checked_separator: ',' # symbol to separate the checked ids
|
116
|
+
})
|
117
|
+
|
118
|
+
# these settings are considered constant for the whole application, can not be overridden
|
119
|
+
# on a per-table basis.
|
120
|
+
# That's necessary to allow find_for_table to work properly
|
121
|
+
PAGINATE_OPTIONS = ActiveSupport::HashWithIndifferentAccess.new({
|
122
|
+
page: 1,
|
123
|
+
pagesize: 10,
|
124
|
+
pagesizes: [10, 20, 50]
|
125
|
+
})
|
126
|
+
|
127
|
+
# Hash keeping the defaults for the column options
|
128
|
+
COLUMN_OPTIONS = ActiveSupport::HashWithIndifferentAccess.new({
|
129
|
+
header: false, # a string to write into the header cell
|
130
|
+
width: false, # the width of the cell
|
131
|
+
align: false, # horizontal alignment
|
132
|
+
valign: false, # vertical alignment
|
133
|
+
wrap: true, # wraps
|
134
|
+
type: :string, # :integer, :date
|
135
|
+
td_html: false, # a hash with html attributes for the cells
|
136
|
+
th_html: false, # a hash with html attributes for the header cell
|
137
|
+
filter_html: false, # a hash with html attributes for the filter cell
|
138
|
+
filter: true, # false for no filter field,
|
139
|
+
# container for options_for_select
|
140
|
+
# String from options_from_collection_for_select or the like
|
141
|
+
# :range for range spec
|
142
|
+
# :checkbox for a 0/1 valued checkbox
|
143
|
+
checkbox_value: '1', # value if checkbox is checked
|
144
|
+
checkbox_label: '', # text behind the checkbox
|
145
|
+
filter_width: '97%', # width of the filter <input>
|
146
|
+
range_filter_symbol: '–', # put between the <inputs> of the range filter
|
147
|
+
format: false, # a sprintf-string or a proc to do special formatting
|
148
|
+
method: false, # if you want to get the column by a different method than its name
|
149
|
+
link: false, # proc or symbol to make the content a link
|
150
|
+
join_symbol: ', ', # symbol used to join the elements of 'many' associations
|
151
|
+
sortable: true # if set, sorting-stuff is added to the header cell
|
152
|
+
})
|
153
|
+
|
154
|
+
# these settings are considered constant for the whole application, can not be overridden
|
155
|
+
# on a per-table basis.
|
156
|
+
# That's necessary to allow find_for_table to work properly
|
157
|
+
FINDER_INJECT_OPTIONS = WhinyHash.new({
|
158
|
+
pagination: :__pagination,
|
159
|
+
filters: :__filters,
|
160
|
+
classname: :__classname,
|
161
|
+
sorting: :__sorting,
|
162
|
+
checked: :__checked,
|
163
|
+
store_data: :__store_data
|
164
|
+
})
|
165
|
+
|
166
|
+
# defaults for the find_for_table
|
167
|
+
FINDER_OPTIONS = WhinyHash.new({
|
168
|
+
default_order: false,
|
169
|
+
default_pagesize: false,
|
170
|
+
precondition: false,
|
171
|
+
store_data: false
|
172
|
+
})
|
173
|
+
|
174
|
+
# Stupid hack
|
175
|
+
SQL_OPTIONS = WhinyHash.new({
|
176
|
+
like: 'LIKE'
|
177
|
+
})
|
178
|
+
|
179
|
+
def self.finder_inject_options(n=nil)
|
180
|
+
FINDER_INJECT_OPTIONS.merge!(n) if n
|
181
|
+
FINDER_INJECT_OPTIONS
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.finder_options(n=nil)
|
185
|
+
FINDER_OPTIONS.merge!(n) if n
|
186
|
+
FINDER_OPTIONS
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.column_options(n=nil)
|
190
|
+
COLUMN_OPTIONS.merge!(n) if n
|
191
|
+
COLUMN_OPTIONS
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.table_options(n=nil)
|
195
|
+
TABLE_OPTIONS.merge!(n) if n
|
196
|
+
TABLE_OPTIONS
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.paginate_options(n=nil)
|
200
|
+
PAGINATE_OPTIONS.merge!(n) if n
|
201
|
+
PAGINATE_OPTIONS
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.table_form_options(n=nil)
|
205
|
+
TABLE_FORM_OPTIONS.merge!(n) if n
|
206
|
+
TABLE_FORM_OPTIONS
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.table_design_options(n=nil)
|
210
|
+
raise("table_design_options stopped existing. Use table_options instead.")
|
211
|
+
end
|
212
|
+
def table_design_options(n=nil) self.class.table_design_options(n) end
|
213
|
+
|
214
|
+
def self.sql_options(n=nil)
|
215
|
+
SQL_OPTIONS.merge!(n) if n
|
216
|
+
SQL_OPTIONS
|
217
|
+
end
|
218
|
+
def sql_options(n=nil) self.class.sql_options(n) end
|
219
|
+
|
220
|
+
|
221
|
+
end
|