cheveret 2.0.0.rc5 → 3.0.0

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.
@@ -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