tabulatr 0.0.1
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.
- 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
|