tangofoxtrot-table_helper 0.2.2
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/CHANGELOG.rdoc +45 -0
- data/LICENSE +20 -0
- data/README.rdoc +171 -0
- data/Rakefile +96 -0
- data/init.rb +1 -0
- data/lib/table_helper.rb +211 -0
- data/lib/table_helper/body.rb +113 -0
- data/lib/table_helper/body_row.rb +74 -0
- data/lib/table_helper/cell.rb +60 -0
- data/lib/table_helper/collection_table.rb +138 -0
- data/lib/table_helper/footer.rb +52 -0
- data/lib/table_helper/header.rb +109 -0
- data/lib/table_helper/html_element.rb +42 -0
- data/lib/table_helper/row.rb +110 -0
- data/test/app_root/app/models/person.rb +2 -0
- data/test/app_root/db/migrate/001_create_people.rb +11 -0
- data/test/helpers/table_helper_test.rb +45 -0
- data/test/test_helper.rb +14 -0
- data/test/unit/body_row_test.rb +155 -0
- data/test/unit/body_test.rb +299 -0
- data/test/unit/cell_test.rb +126 -0
- data/test/unit/collection_table_test.rb +228 -0
- data/test/unit/footer_test.rb +110 -0
- data/test/unit/header_test.rb +270 -0
- data/test/unit/html_element_test.rb +74 -0
- data/test/unit/row_builder_test.rb +55 -0
- data/test/unit/row_test.rb +204 -0
- metadata +97 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'table_helper/body_row'
|
2
|
+
|
3
|
+
module TableHelper
|
4
|
+
# Represents the body of the table. In HTML, you can think of this as
|
5
|
+
# the <tbody> tag of the table.
|
6
|
+
class Body < HtmlElement
|
7
|
+
# The css class to apply for all rows in the body
|
8
|
+
cattr_accessor :empty_caption_class
|
9
|
+
@@empty_caption_class = 'ui-collection-empty'
|
10
|
+
|
11
|
+
# The table this body is a part of
|
12
|
+
attr_reader :table
|
13
|
+
|
14
|
+
# If set to :odd or :even, every odd or even-numbered row will have the
|
15
|
+
# alternate class appended to its html attributes. Default is nil.
|
16
|
+
attr_accessor :alternate
|
17
|
+
|
18
|
+
# The caption to display in the collection is empty
|
19
|
+
attr_accessor :empty_caption
|
20
|
+
|
21
|
+
def initialize(table) #:nodoc:
|
22
|
+
super()
|
23
|
+
|
24
|
+
@table = table
|
25
|
+
@empty_caption = 'No matches found.'
|
26
|
+
end
|
27
|
+
|
28
|
+
def alternate=(value) #:nodoc:
|
29
|
+
raise ArgumentError, 'alternate must be set to :odd or :even' if value && ![:odd, :even].include?(value)
|
30
|
+
@alternate = value
|
31
|
+
end
|
32
|
+
|
33
|
+
# Builds the body of the table. This includes the actual data that is
|
34
|
+
# generated for each object in the collection.
|
35
|
+
#
|
36
|
+
# +each+ expects a block that defines the data in each cell. Each
|
37
|
+
# iteration of the block will provide the row within the table, the object
|
38
|
+
# being rendered, and the index of the object. For example,
|
39
|
+
#
|
40
|
+
# t.rows.each do |row, post, index|
|
41
|
+
# row.title "<div class=\"wrapped\">#{post.title}</div>"
|
42
|
+
# row.category post.category.name
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# In addition, to specifying the data, you can also modify the html
|
46
|
+
# options of the row. For more information on doing this, see the
|
47
|
+
# BodyRow class.
|
48
|
+
#
|
49
|
+
# If the collection is empty and +empty_caption+ is set on the body,
|
50
|
+
# then the actual body will be replaced by a single row containing the
|
51
|
+
# html that was stored in +empty_caption+.
|
52
|
+
#
|
53
|
+
# == Default Values
|
54
|
+
#
|
55
|
+
# Whenever possible, the default value of a cell will be set to the
|
56
|
+
# object's attribute with the same name as the cell. For example,
|
57
|
+
# if a Post consists of the attribute +title+, then the cell for the
|
58
|
+
# title will be prepopulated with that attribute's value:
|
59
|
+
#
|
60
|
+
# t.rows.each do |row, post index|
|
61
|
+
# row.title post.title
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# <tt>row.title</tt> is already set to post.category so there's no need to
|
65
|
+
# manually set the value of that cell. However, it is always possible
|
66
|
+
# to override the default value like so:
|
67
|
+
#
|
68
|
+
# t.rows.each do |row, post, index|
|
69
|
+
# row.title link_to(post.title, post_url(post))
|
70
|
+
# row.category post.category.name
|
71
|
+
# end
|
72
|
+
def each(&block)
|
73
|
+
@builder = block
|
74
|
+
end
|
75
|
+
|
76
|
+
# Builds a row for an object in the table.
|
77
|
+
#
|
78
|
+
# The provided block should set the values for each cell in the row.
|
79
|
+
def build_row(object, index = table.collection.index(object))
|
80
|
+
row = BodyRow.new(object, self)
|
81
|
+
row.alternate = alternate ? index.send("#{alternate}?") : false
|
82
|
+
@builder.call(row.builder, object, index) if @builder
|
83
|
+
row.html
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def tag_name
|
88
|
+
'tbody'
|
89
|
+
end
|
90
|
+
|
91
|
+
def content
|
92
|
+
content = ''
|
93
|
+
|
94
|
+
if table.empty? && @empty_caption
|
95
|
+
# No objects to display
|
96
|
+
row = Row.new(self)
|
97
|
+
row[:class] = empty_caption_class
|
98
|
+
|
99
|
+
html_options = {}
|
100
|
+
html_options[:colspan] = table.header.columns.size if table.header.columns.size > 1
|
101
|
+
row.cell nil, @empty_caption, html_options
|
102
|
+
|
103
|
+
content << row.html
|
104
|
+
else
|
105
|
+
table.collection.each_with_index do |object, i|
|
106
|
+
content << build_row(object, i)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
content
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'table_helper/row'
|
2
|
+
|
3
|
+
module TableHelper
|
4
|
+
# Represents a single row within the body of a table. The row can consist
|
5
|
+
# of either data cells or header cells.
|
6
|
+
#
|
7
|
+
# == Alternating rows
|
8
|
+
#
|
9
|
+
# Alternating rows can be automated by setting the +alternate+ property.
|
10
|
+
# For example,
|
11
|
+
#
|
12
|
+
# r = BodyRow.new(object, parent)
|
13
|
+
# r.alternate = true
|
14
|
+
class BodyRow < Row
|
15
|
+
# The css class to apply for all rows in the body
|
16
|
+
cattr_accessor :result_class
|
17
|
+
@@result_class = 'ui-collection-result'
|
18
|
+
|
19
|
+
# The css class to apply for rows that are marked as "alternate"
|
20
|
+
cattr_accessor :alternate_class
|
21
|
+
@@alternate_class = 'ui-state-alternate'
|
22
|
+
|
23
|
+
# True if this is an alternating row, otherwise false. Default is false.
|
24
|
+
attr_accessor :alternate
|
25
|
+
|
26
|
+
def initialize(object, parent) #:nodoc:
|
27
|
+
super(parent)
|
28
|
+
|
29
|
+
@alternate = false
|
30
|
+
self[:class] = "#{self[:class]} #{table.object_name} #{result_class}".strip
|
31
|
+
|
32
|
+
# For each column defined in the table, see if we can prepopulate the
|
33
|
+
# cell based on the data in the object. If not, we can at least
|
34
|
+
# provide shortcut accessors to the cell
|
35
|
+
table.header.column_names.each do |column|
|
36
|
+
value = object.respond_to?(column) ? object.send(column) : nil
|
37
|
+
cell(column, value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Generates the html for this row in additional to the border row
|
42
|
+
# (if specified)
|
43
|
+
def html
|
44
|
+
original_options = @html_options.dup
|
45
|
+
self[:class] = "#{self[:class]} #{alternate_class}".strip if alternate
|
46
|
+
html = super
|
47
|
+
@html_options = original_options
|
48
|
+
html
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
# Builds the row's cells based on the order of the columns in the
|
53
|
+
# header. If a cell cannot be found for a specific column, then a blank
|
54
|
+
# cell is rendered.
|
55
|
+
def content
|
56
|
+
number_to_skip = 0 # Keeps track of the # of columns to skip
|
57
|
+
|
58
|
+
html = ''
|
59
|
+
table.header.column_names.each do |column|
|
60
|
+
number_to_skip -= 1 and next if number_to_skip > 0
|
61
|
+
|
62
|
+
if cell = @cells[column]
|
63
|
+
number_to_skip = (cell[:colspan] || 1) - 1
|
64
|
+
else
|
65
|
+
cell = Cell.new(column, nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
html << cell.html
|
69
|
+
end
|
70
|
+
|
71
|
+
html
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module TableHelper
|
2
|
+
# Represents a single cell within a table. This can either be a regular
|
3
|
+
# data cell (td) or a header cell (th). By default, all cells will have
|
4
|
+
# their name appended to the cell's class attribute.
|
5
|
+
#
|
6
|
+
# == Examples
|
7
|
+
#
|
8
|
+
# # Data cell
|
9
|
+
# c = Cell.new(:author, 'John Doe')
|
10
|
+
# c.html # => <td class="author">John Doe</td>
|
11
|
+
#
|
12
|
+
# # Header cell
|
13
|
+
# c = Cell.new(:author, 'Author Name')
|
14
|
+
# c.content_type = :header
|
15
|
+
# c.html
|
16
|
+
#
|
17
|
+
# # With namespace
|
18
|
+
# c = Cell.new(:author, :namespace => 'post')
|
19
|
+
# c.content_type = :header
|
20
|
+
# c.html # => <td class="post-author">Author</td>
|
21
|
+
class Cell < HtmlElement
|
22
|
+
# The css class to apply to empty cells
|
23
|
+
cattr_accessor :empty_class
|
24
|
+
@@empty_class = 'ui-state-empty'
|
25
|
+
|
26
|
+
# The content to display within the cell
|
27
|
+
attr_reader :content
|
28
|
+
|
29
|
+
# The type of content this cell represents (:data or :header)
|
30
|
+
attr_reader :content_type
|
31
|
+
|
32
|
+
def initialize(name, content = name.to_s.titleize, html_options = {}) #:nodoc
|
33
|
+
html_options, content = content, name.to_s.titleize if content.is_a?(Hash)
|
34
|
+
namespace = html_options.delete(:namespace)
|
35
|
+
super(html_options)
|
36
|
+
|
37
|
+
@content = content.to_s
|
38
|
+
|
39
|
+
if name
|
40
|
+
name = "#{namespace}-#{name}" unless namespace.blank?
|
41
|
+
self[:class] = "#{self[:class]} #{name}".strip
|
42
|
+
end
|
43
|
+
self[:class] = "#{self[:class]} #{empty_class}".strip if content.blank?
|
44
|
+
|
45
|
+
self.content_type = :data
|
46
|
+
end
|
47
|
+
|
48
|
+
# Indicates what type of content will be stored in this cell. This can
|
49
|
+
# be set to either :data or :header.
|
50
|
+
def content_type=(value)
|
51
|
+
raise ArgumentError, "content_type must be set to :data or :header, was: #{value.inspect}" unless [:data, :header].include?(value)
|
52
|
+
@content_type = value
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def tag_name
|
57
|
+
@content_type == :data ? 'td' : 'th'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'table_helper/html_element'
|
2
|
+
require 'table_helper/header'
|
3
|
+
require 'table_helper/body'
|
4
|
+
require 'table_helper/footer'
|
5
|
+
|
6
|
+
module TableHelper
|
7
|
+
# Represents a table that displays data for multiple objects within a
|
8
|
+
# collection.
|
9
|
+
class CollectionTable < HtmlElement
|
10
|
+
# The css class to apply for all menu bars
|
11
|
+
cattr_accessor :collection_class
|
12
|
+
@@collection_class = 'ui-collection'
|
13
|
+
|
14
|
+
# The class of objects that will be rendered in the table
|
15
|
+
attr_reader :klass
|
16
|
+
|
17
|
+
# The name of the objects in the collection. By default, this is the
|
18
|
+
# underscored name of the class of objects being rendered. This value is
|
19
|
+
# used for generates parts of the css classes in the table, such as rows
|
20
|
+
# and cells.
|
21
|
+
#
|
22
|
+
# For example, if the class is Post, then the object name will be "post".
|
23
|
+
attr_accessor :object_name
|
24
|
+
|
25
|
+
# The actual collection of objects being rendered in the table's body.
|
26
|
+
# This collection will also be used to help automatically determine what
|
27
|
+
# the class is.
|
28
|
+
attr_reader :collection
|
29
|
+
|
30
|
+
# The body of rows that will be generated for each object in the
|
31
|
+
# collection. The actual content for each row and the html options can
|
32
|
+
# be configured as well.
|
33
|
+
#
|
34
|
+
# See TableHelper::Body for more information.
|
35
|
+
#
|
36
|
+
# == Examples
|
37
|
+
#
|
38
|
+
# # Defining rows
|
39
|
+
# t.rows.each do |row, post, index|
|
40
|
+
# row.category post.category.name
|
41
|
+
# row.author post.author.name
|
42
|
+
# ...
|
43
|
+
# row[:style] = 'margin-top: 5px;'
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # Customizing html options
|
47
|
+
# t.rows[:class] = 'pretty'
|
48
|
+
attr_reader :rows
|
49
|
+
|
50
|
+
# Creates a new table based on the objects within the given collection
|
51
|
+
def initialize(collection, klass = nil, html_options = {}) #:nodoc:
|
52
|
+
html_options, klass = klass, nil if klass.is_a?(Hash)
|
53
|
+
super(html_options)
|
54
|
+
|
55
|
+
@collection = collection
|
56
|
+
@klass = klass || default_class
|
57
|
+
@object_name = @klass ? @klass.name.split('::').last.underscore : nil
|
58
|
+
@html_options.reverse_merge!(:cellspacing => '0', :cellpadding => '0')
|
59
|
+
|
60
|
+
self[:class] = "#{self[:class]} #{@object_name.pluralize}".strip if @object_name
|
61
|
+
self[:class] = "#{self[:class]} #{collection_class}".strip
|
62
|
+
|
63
|
+
# Build actual content
|
64
|
+
@header = Header.new(self)
|
65
|
+
@rows = Body.new(self)
|
66
|
+
@footer = Footer.new(self)
|
67
|
+
|
68
|
+
yield self if block_given?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Will any rows be generated in the table's body?
|
72
|
+
def empty?
|
73
|
+
collection.empty?
|
74
|
+
end
|
75
|
+
|
76
|
+
# Creates a new header cell with the given name. Headers must be defined
|
77
|
+
# in the order in which they will be rendered.
|
78
|
+
#
|
79
|
+
# The actual caption and html options for the header can be configured
|
80
|
+
# as well. The caption determines what will be displayed in each cell.
|
81
|
+
#
|
82
|
+
# == Examples
|
83
|
+
#
|
84
|
+
# # Adding headers
|
85
|
+
# t.header :title # => <th class="post-title">Title</th>
|
86
|
+
# t.header :title, 'The Title' # => <th class="post-title">The Title</th>
|
87
|
+
# t.header :title, :class => 'pretty' # => <th class="post-title pretty">Title</th>
|
88
|
+
# t.header :title, 'The Title', :class => 'pretty' # => <th class="post-title pretty">The Title</th>
|
89
|
+
#
|
90
|
+
# # Customizing html options
|
91
|
+
# t.header[:class] = 'pretty'
|
92
|
+
def header(*args)
|
93
|
+
args.empty? ? @header : @header.column(*args)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a new footer cell with the given name. Footers must be defined
|
97
|
+
# in the order in which they will be rendered.
|
98
|
+
#
|
99
|
+
# The actual caption and html options for the footer can be configured
|
100
|
+
# as well. The caption determines what will be displayed in each cell.
|
101
|
+
#
|
102
|
+
# == Examples
|
103
|
+
#
|
104
|
+
# # Adding footers
|
105
|
+
# t.footer :total # => <td class="post-total"></th>
|
106
|
+
# t.footer :total, 5 # => <td class="post-total">5</th>
|
107
|
+
# t.footer :total, :class => 'pretty' # => <td class="post-total pretty"></th>
|
108
|
+
# t.footer :total, 5, :class => 'pretty' # => <td class="post-total pretty">5</th>
|
109
|
+
#
|
110
|
+
# # Customizing html options
|
111
|
+
# t.footer[:class] = 'pretty'
|
112
|
+
def footer(*args)
|
113
|
+
args.empty? ? @footer : @footer.cell(*args)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
# Finds the class representing the objects within the collection
|
118
|
+
def default_class
|
119
|
+
if collection.respond_to?(:proxy_reflection)
|
120
|
+
collection.proxy_reflection.klass
|
121
|
+
elsif !collection.empty?
|
122
|
+
collection.first.class
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def tag_name
|
127
|
+
'table'
|
128
|
+
end
|
129
|
+
|
130
|
+
def content
|
131
|
+
content = ''
|
132
|
+
content << @header.html unless @header.empty?
|
133
|
+
content << @rows.html
|
134
|
+
content << @footer.html unless @footer.empty?
|
135
|
+
content
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'table_helper/row'
|
2
|
+
|
3
|
+
module TableHelper
|
4
|
+
# Represents the header of the table. In HTML, you can think of this as
|
5
|
+
# the <tfoot> tag of the table.
|
6
|
+
class Footer < HtmlElement
|
7
|
+
# The table this footer is a part of
|
8
|
+
attr_reader :table
|
9
|
+
|
10
|
+
# The actual footer row
|
11
|
+
attr_reader :row
|
12
|
+
|
13
|
+
# Whether or not the footer should be hidden when the collection is
|
14
|
+
# empty. Default is true.
|
15
|
+
attr_accessor :hide_when_empty
|
16
|
+
|
17
|
+
delegate :cell, :empty?, :to => :row
|
18
|
+
|
19
|
+
def initialize(table) #:nodoc:
|
20
|
+
super()
|
21
|
+
|
22
|
+
@table = table
|
23
|
+
@row = Row.new(self)
|
24
|
+
@hide_when_empty = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def html #:nodoc:
|
28
|
+
# Force the last cell to span the remaining columns
|
29
|
+
cells = row.cells.values
|
30
|
+
colspan = table.header.columns.length - cells[0..-2].inject(0) {|count, cell| count += (cell[:colspan] || 1).to_i}
|
31
|
+
cells.last[:colspan] ||= colspan if colspan > 1
|
32
|
+
|
33
|
+
html_options = @html_options.dup
|
34
|
+
html_options[:style] = "display: none; #{html_options[:style]}".strip if table.empty? && hide_when_empty
|
35
|
+
|
36
|
+
content_tag(tag_name, content, html_options)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def tag_name
|
41
|
+
'tfoot'
|
42
|
+
end
|
43
|
+
|
44
|
+
# Generates the html for the footer. The footer generally consists of a
|
45
|
+
# summary of the data in the body. This row will be wrapped inside of
|
46
|
+
# a tfoot tag. If the collection is empty and hide_when_empty was set
|
47
|
+
# to true, then the footer will be hidden.
|
48
|
+
def content
|
49
|
+
@row.html
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'table_helper/row'
|
2
|
+
|
3
|
+
module TableHelper
|
4
|
+
# Represents the header of the table. In HTML, you can think of this as
|
5
|
+
# the <thead> tag of the table.
|
6
|
+
class Header < HtmlElement
|
7
|
+
# The table this header is a part of
|
8
|
+
attr_reader :table
|
9
|
+
|
10
|
+
# The actual header row
|
11
|
+
attr_reader :row
|
12
|
+
|
13
|
+
# Whether or not the header should be hidden when the collection is
|
14
|
+
# empty. Default is true.
|
15
|
+
attr_accessor :hide_when_empty
|
16
|
+
|
17
|
+
delegate :empty?, :to => :row
|
18
|
+
|
19
|
+
# Creates a new header for the given table.
|
20
|
+
#
|
21
|
+
# If the class is known, then the header will be pre-filled with
|
22
|
+
# the columns defined in that class (assuming it's an ActiveRecord
|
23
|
+
# class).
|
24
|
+
def initialize(table)
|
25
|
+
super()
|
26
|
+
|
27
|
+
@table = table
|
28
|
+
@row = Row.new(self)
|
29
|
+
@hide_when_empty = true
|
30
|
+
|
31
|
+
# If we know what class the objects in the collection are and we can
|
32
|
+
# figure out what columns are defined in that class, then we can
|
33
|
+
# pre-fill the header with those columns so that the user doesn't
|
34
|
+
# have to
|
35
|
+
klass = table.klass
|
36
|
+
if klass && klass.respond_to?(:column_names)
|
37
|
+
if !table.empty? && klass < ActiveRecord::Base
|
38
|
+
# Make sure only the attributes that have been loaded are used
|
39
|
+
column_names = table.collection.first.attributes.keys
|
40
|
+
else
|
41
|
+
# Assume all attributes are loaded
|
42
|
+
column_names = klass.column_names
|
43
|
+
end
|
44
|
+
|
45
|
+
column(*column_names.map(&:to_sym))
|
46
|
+
end
|
47
|
+
|
48
|
+
@customized = false
|
49
|
+
end
|
50
|
+
|
51
|
+
# The current columns in this header, in the order in which they will be
|
52
|
+
# built
|
53
|
+
def columns
|
54
|
+
row.cells
|
55
|
+
end
|
56
|
+
|
57
|
+
# Gets the names of all of the columns being displayed in the table
|
58
|
+
def column_names
|
59
|
+
row.cell_names
|
60
|
+
end
|
61
|
+
|
62
|
+
# Clears all of the current columns from the header
|
63
|
+
def clear
|
64
|
+
row.clear
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates one or more to columns in the header. This will clear any
|
68
|
+
# pre-existing columns if it is being customized for the first time after
|
69
|
+
# it was initially created.
|
70
|
+
def column(*names)
|
71
|
+
# Clear the header row if this is being customized by the user
|
72
|
+
unless @customized
|
73
|
+
@customized = true
|
74
|
+
clear
|
75
|
+
end
|
76
|
+
|
77
|
+
# Extract configuration
|
78
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
79
|
+
content = names.last.is_a?(String) ? names.pop : nil
|
80
|
+
args = [content, options].compact
|
81
|
+
|
82
|
+
names.collect! do |name|
|
83
|
+
column = row.cell(name, *args)
|
84
|
+
column.content_type = :header
|
85
|
+
column[:scope] ||= 'col'
|
86
|
+
column
|
87
|
+
end
|
88
|
+
|
89
|
+
names.length == 1 ? names.first : names
|
90
|
+
end
|
91
|
+
|
92
|
+
# Creates and returns the generated html for the header
|
93
|
+
def html
|
94
|
+
html_options = @html_options.dup
|
95
|
+
html_options[:style] = 'display: none;' if table.empty? && hide_when_empty
|
96
|
+
|
97
|
+
content_tag(tag_name, content, html_options)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def tag_name
|
102
|
+
'thead'
|
103
|
+
end
|
104
|
+
|
105
|
+
def content
|
106
|
+
@row.html
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|