cheveret 2.0.0.rc5 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/cheveret.gemspec +14 -9
- data/lib/cheveret.rb +24 -8
- data/lib/cheveret/{filtering.rb → adapter/active_record.rb} +5 -16
- data/lib/cheveret/adapter/sunspot.rb +57 -0
- data/lib/cheveret/{config.rb → builder/divider.rb} +16 -19
- data/lib/cheveret/column.rb +10 -25
- data/lib/cheveret/helper.rb +47 -8
- data/lib/cheveret/table.rb +47 -0
- data/lib/cheveret/table/columns.rb +77 -0
- data/lib/cheveret/table/data.rb +62 -0
- data/lib/cheveret/{base.rb → table/locale.rb} +24 -27
- data/lib/cheveret/table/mapping.rb +88 -0
- data/lib/cheveret/table/rendering.rb +122 -0
- data/lib/cheveret/table/sizing.rb +136 -0
- data/lib/cheveret/table/sorting.rb +124 -0
- data/lib/cheveret/version.rb +2 -3
- metadata +20 -18
- data/lib/cheveret/dsl.rb +0 -124
- data/lib/cheveret/rendering.rb +0 -85
- data/lib/cheveret/resizing.rb +0 -97
@@ -21,37 +21,34 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
-
require 'active_support/ordered_hash'
|
25
|
-
|
26
24
|
module Cheveret
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def initialize(template, &block)
|
31
|
-
@template = template
|
32
|
-
@columns = ::ActiveSupport::OrderedHash.new
|
33
|
-
|
34
|
-
instance_eval(&block) if block_given?
|
35
|
-
end
|
25
|
+
module Table
|
26
|
+
module Locale
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
28
|
+
##
|
29
|
+
#
|
30
|
+
#
|
31
|
+
def render_th(column, options={})
|
32
|
+
unless options[:title]
|
33
|
+
scope = self.class.to_s.sub(/Table\Z/, '').underscore
|
34
|
+
hint = ::I18n.translate("cheveret.hints.#{scope}.#{column.name}",
|
35
|
+
:default => '')
|
43
36
|
|
44
|
-
|
37
|
+
options[:title] = hint.squish unless hint.blank?
|
38
|
+
end
|
45
39
|
|
46
|
-
# since the define_table block gets instance_eval'd in the context of this object
|
47
|
-
# we need to proxy view methods (e.g. check_box_tag) back to the template
|
48
|
-
def method_missing(method_name, *args, &block) #:nodoc:
|
49
|
-
if @template.respond_to?(method_name)
|
50
|
-
@template.send(method_name, *args, &block)
|
51
|
-
else
|
52
40
|
super
|
53
41
|
end
|
54
|
-
end
|
55
42
|
|
56
|
-
|
57
|
-
|
43
|
+
##
|
44
|
+
#
|
45
|
+
#
|
46
|
+
def table_header_for(column)
|
47
|
+
scope = self.class.to_s.sub(/Table\Z/, '').underscore
|
48
|
+
header = ::I18n.translate("cheveret.headers.#{scope}.#{column.name}",
|
49
|
+
:default => column.name.to_s.humanize).squish
|
50
|
+
end
|
51
|
+
|
52
|
+
end # Locale
|
53
|
+
end # Table
|
54
|
+
end # Cheveret
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 RateCity Pty. Ltd.
|
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 Cheveret
|
25
|
+
module Table
|
26
|
+
module Mapping
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
::Cheveret::Column.send :include, Mappable
|
30
|
+
end
|
31
|
+
|
32
|
+
module Mappable
|
33
|
+
attr_accessor :data, :header
|
34
|
+
end # Mappable
|
35
|
+
|
36
|
+
##
|
37
|
+
#
|
38
|
+
#
|
39
|
+
def table_data(column, item)
|
40
|
+
args = [ item ]
|
41
|
+
|
42
|
+
case column.data
|
43
|
+
when Symbol
|
44
|
+
args.unshift(column) if method(column.data).arity > 1
|
45
|
+
send(column.data, *args)
|
46
|
+
when Proc
|
47
|
+
args.unshift(column) if column.data.arity > 1
|
48
|
+
template.capture(*args, &column.data)
|
49
|
+
else
|
50
|
+
if respond_to?(column.name)
|
51
|
+
args.unshift(column) if method(column.name).arity > 1
|
52
|
+
send(column.name, *args)
|
53
|
+
else
|
54
|
+
table_data_for(column, item)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
#
|
61
|
+
#
|
62
|
+
def table_data_for(column, item)
|
63
|
+
raise NotImplementedError
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
#
|
68
|
+
#
|
69
|
+
def table_header(column)
|
70
|
+
case column.header
|
71
|
+
when Symbol then send(column.header)
|
72
|
+
when Proc then template.capture(&column.header)
|
73
|
+
when String then column.header
|
74
|
+
else
|
75
|
+
table_header_for(column) unless column.header == false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
#
|
81
|
+
#
|
82
|
+
def table_header_for(column)
|
83
|
+
raise NotImplementedError
|
84
|
+
end
|
85
|
+
|
86
|
+
end # Mapping
|
87
|
+
end # Table
|
88
|
+
end # Cheveret
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 RateCity Pty. Ltd.
|
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 Cheveret
|
25
|
+
module Table
|
26
|
+
module Rendering
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.module_eval do
|
30
|
+
extend ClassMethods
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_accessor :template
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
end # ClassMethods
|
38
|
+
|
39
|
+
##
|
40
|
+
#
|
41
|
+
#
|
42
|
+
def render_table(options={})
|
43
|
+
table_tag(options) do
|
44
|
+
render_thead << render_tbody
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
#
|
50
|
+
#
|
51
|
+
def render_thead(options={})
|
52
|
+
thead_tag(options) do
|
53
|
+
tr_tag do
|
54
|
+
columns.values.map do |column|
|
55
|
+
render_th(column) { table_header(column) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
#
|
63
|
+
#
|
64
|
+
def render_tbody(options={})
|
65
|
+
tbody_tag(options) { render_rows }
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
#
|
70
|
+
#
|
71
|
+
def render_rows(options={})
|
72
|
+
template.reset_cycle('cheveret')
|
73
|
+
|
74
|
+
collection.map do |item|
|
75
|
+
cycle = template.cycle('', 'alt', :name => 'cheveret')
|
76
|
+
|
77
|
+
tr_tag(:class => cycle) do
|
78
|
+
columns.values.map do |column|
|
79
|
+
render_td(column) { table_data(column, item) }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end.join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# generates a <th> tag for the specified column using the configured builder
|
87
|
+
#
|
88
|
+
def render_th(column, options={})
|
89
|
+
options.reverse_merge!(column.th_html) if column.th_html
|
90
|
+
|
91
|
+
# phwarrrgg!
|
92
|
+
options[:class] = ([ column.name, options[:class],
|
93
|
+
column.th_html ? column.th_html[:class] : nil
|
94
|
+
]).flatten.join(' ').strip
|
95
|
+
|
96
|
+
th_tag(options) { yield }
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
#
|
101
|
+
#
|
102
|
+
def render_td(column, options={})
|
103
|
+
options.reverse_merge!(column.td_html) if column.td_html
|
104
|
+
options[:class] = [ column.name, *options[:class] ].flatten.join(' ').strip
|
105
|
+
|
106
|
+
td_tag(options) { yield }
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
#
|
111
|
+
#
|
112
|
+
def render(*args, &block)
|
113
|
+
if args.empty? && block_given?
|
114
|
+
template.instance_eval(&block)
|
115
|
+
else
|
116
|
+
template.render(*args, &block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end # Rendering
|
121
|
+
end # Table
|
122
|
+
end # Cheveret
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 RateCity Pty. Ltd.
|
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 Cheveret
|
25
|
+
module Table
|
26
|
+
module Sizing
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.module_eval do
|
30
|
+
extend ClassMethods
|
31
|
+
end
|
32
|
+
|
33
|
+
# allow columns to be flexible and/or have their width set
|
34
|
+
::Cheveret::Column.send :include, Sizable
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :width
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
|
41
|
+
# todo: set width?
|
42
|
+
|
43
|
+
end # ClassMethods
|
44
|
+
|
45
|
+
module Sizable
|
46
|
+
attr_accessor :flexible, :size, :width
|
47
|
+
|
48
|
+
##
|
49
|
+
#
|
50
|
+
#
|
51
|
+
def flexible?
|
52
|
+
@flexible == true
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
#
|
57
|
+
#
|
58
|
+
def size
|
59
|
+
@size || width
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
#
|
64
|
+
#
|
65
|
+
def width
|
66
|
+
@width || 0
|
67
|
+
end
|
68
|
+
|
69
|
+
end # Sizable
|
70
|
+
|
71
|
+
##
|
72
|
+
#
|
73
|
+
#
|
74
|
+
def width
|
75
|
+
@width ||= 0
|
76
|
+
end
|
77
|
+
|
78
|
+
[ :table, :thead, :tbody, :rows].each do |elem|
|
79
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
80
|
+
def render_#{elem}(options={})
|
81
|
+
resize! if needs_resize?
|
82
|
+
|
83
|
+
options[:style] = "width:\#{width}px;" if width > 0
|
84
|
+
super
|
85
|
+
end
|
86
|
+
RUBY_EVAL
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
#
|
91
|
+
#
|
92
|
+
def render_th(column, options={})
|
93
|
+
options[:style] = "width:#{column.size}px;" if column.size > 0
|
94
|
+
super
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
#
|
99
|
+
#
|
100
|
+
def render_td(column, options={})
|
101
|
+
options[:style] = "width:#{column.size}px;" if column.size > 0
|
102
|
+
super
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
#
|
107
|
+
#
|
108
|
+
def resize!
|
109
|
+
columns_width, flexibles = 0, []
|
110
|
+
|
111
|
+
columns.values.each do |column|
|
112
|
+
columns_width += column.width
|
113
|
+
flexibles << column if column.flexible?
|
114
|
+
end
|
115
|
+
|
116
|
+
# todo: handle too-many/too-wide columns
|
117
|
+
raise "uh-oh spaghettio-s" if columns_width > width
|
118
|
+
|
119
|
+
# todo: fix rounding in with calculation
|
120
|
+
if columns_width < width && !flexibles.empty?
|
121
|
+
padding = (width - columns_width) / flexibles.length
|
122
|
+
flexibles.each { |column| column.size = column.width + padding }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
#
|
128
|
+
#
|
129
|
+
def needs_resize?
|
130
|
+
columns.map(&:size).sum != width
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
end # Sizing
|
135
|
+
end # Table
|
136
|
+
end # Cheveret
|
@@ -0,0 +1,124 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 RateCity Pty. Ltd.
|
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 Cheveret
|
25
|
+
module Table
|
26
|
+
module Sorting
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.module_eval do
|
30
|
+
extend ClassMethods
|
31
|
+
end
|
32
|
+
|
33
|
+
# make sure our column objects can be configured as sortable
|
34
|
+
::Cheveret::Column.send :include, Sortable
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :sort_column, :sort_direction, :sort_param, :sort_url
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
|
41
|
+
##
|
42
|
+
# defines which table columns can be sorted by the user
|
43
|
+
#
|
44
|
+
def sortable_on(*args)
|
45
|
+
args.each do |column_name|
|
46
|
+
raise "unrecognised column #{column_name}" unless columns[column_name]
|
47
|
+
columns[column_name].sortable = true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# TODO: depricate
|
53
|
+
#
|
54
|
+
def default_sort(column_name, direction)
|
55
|
+
raise ArgumentError 'Column not found' unless columns.has_key?(column_name)
|
56
|
+
|
57
|
+
@default_sort_column = columns[column_name]
|
58
|
+
@default_sort_direction = direction
|
59
|
+
end
|
60
|
+
|
61
|
+
end # ClassMethods
|
62
|
+
|
63
|
+
module Sortable
|
64
|
+
attr_accessor :default_sort_direction, :sortable
|
65
|
+
|
66
|
+
##
|
67
|
+
# whether or not sorting the table by this column is allowed. default +false+
|
68
|
+
#
|
69
|
+
def sortable?
|
70
|
+
sortable == true
|
71
|
+
end
|
72
|
+
|
73
|
+
def default_sort_direction
|
74
|
+
@default_sort_direction ||= :desc
|
75
|
+
end
|
76
|
+
|
77
|
+
end # Sortable
|
78
|
+
|
79
|
+
##
|
80
|
+
#
|
81
|
+
#
|
82
|
+
def sort_param
|
83
|
+
@sort_param ||= '%s'
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
#
|
88
|
+
#
|
89
|
+
def render_th(column, options={})
|
90
|
+
return super unless column.sortable?
|
91
|
+
|
92
|
+
options[:class] = [ 'sortable', *options[:class] ]
|
93
|
+
options[:class] << 'sorted' if column.name == sort_column
|
94
|
+
options[:class].flatten.join(' ').strip
|
95
|
+
|
96
|
+
super
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
#
|
101
|
+
#
|
102
|
+
def table_header(column)
|
103
|
+
# wrap unsortable columns in a <span> tag
|
104
|
+
return template.content_tag(:span, super) unless column.sortable?
|
105
|
+
|
106
|
+
column_key = sort_param % 'sort_column'
|
107
|
+
direction_key = sort_param % 'sort_direction'
|
108
|
+
|
109
|
+
attrs = {}
|
110
|
+
query = { column_key => column.name,
|
111
|
+
direction_key => column.default_sort_direction }
|
112
|
+
|
113
|
+
if column.name == sort_column
|
114
|
+
query[direction_key] = ( sort_direction == :asc ? :desc : :asc )
|
115
|
+
attrs[:class] = "#{sort_direction}"
|
116
|
+
end
|
117
|
+
|
118
|
+
attrs[:href] = template.url_for(sort_url.merge(query))
|
119
|
+
template.content_tag(:a, super, attrs)
|
120
|
+
end
|
121
|
+
|
122
|
+
end # Sorting
|
123
|
+
end # Table
|
124
|
+
end # Cheveret
|