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.
@@ -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
- class Base
28
- attr_accessor :columns
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
- include DSL
38
- include Rendering
39
- include Config
40
- include Resizing
41
- include Filtering
42
- # include Sorting
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
- protected
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
- end
57
- end
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