Skip to content

Instantly share code, notes, and snippets.

@mark
Created August 21, 2012 19:29
Show Gist options
  • Save mark/3418544 to your computer and use it in GitHub Desktop.
Save mark/3418544 to your computer and use it in GitHub Desktop.
module TableBuilderHelper
def column(options = {}, &block)
@table ||= TableBuilderHelper::TableBuilder.new(self)
@table.add_column(options, block)
end
def row_dom_id(&block)
@table ||= TableBuilderHelper::TableBuilder.new(self)
@table.set_row_dom_id_method(block)
end
def table(contents = [])
the_table = @table
@table = nil
the_table.generate(contents, @requester)
end
#####################
# #
# == TableColumn == #
# #
#####################
class TableColumn
include ActionView::Helpers::TagHelper
attr_reader :options
SORTABLE_CLASS = 'sortable'
def initialize(options, cell_contents_block, view)
@options = options
@cell_contents_block = cell_contents_block
@view = view
end
def contents_for(item)
@view.capture(item, &@cell_contents_block)
end
# Sorting
def order
in_order = options[:order]
unordered = options[:unordered]
if in_order == nil
[ 2, unordered ]
elsif in_order >= 0
[ 1, in_order ]
else # if in_order < 0
[ 3, in_order ]
end
end
def <=>(other)
order <=> other.order
end
###################
# #
# Builder Methods #
# #
###################
def header_options
styles = []
styles << 'display: none' if options[:hidden]
Hash.new.tap do |opts|
opts[:style] = styles.join('; ') unless styles.empty?
css_classes = []
css_classes << options[:css_class] if options[:css_class]
opts[:class] = css_classes.join(' ') unless css_classes.empty?
end
end
def header_cell(html, page_requester)
html.th(header_options) do
if options[:sortable]
href = (options[:sortable] == page_requester.current_order) ? page_requester.for_toggled_ascending : page_requester.for_order( options[:sortable] )
css_class = SORTABLE_CLASS
css_class += ' ' + page_requester.current_ascending_css_class if options[:sortable] == page_requester.current_order
html.a :href => href, :class => css_class do
html << (options[:header] || String.new)
end
else
html << (options[:header] || String.new)
end
end
end
def cell_options
Hash.new.tap do |opts|
opts[:style] = "display: none;" if options[:hidden]
opts[:class] = options[:css_class] if options[:css_class]
opts[:colspan] = options[:colspan] if options[:colspan]
end
end
def content_cell(html, item)
options = cell_options
unless cell_options.fetch(:colspan, 1) == 0
html.td(cell_options) do
html << contents_for(item)
end
end
end
end
######################
# #
# == TableBuilder == #
# #
######################
class TableBuilder
attr_reader :columns
def initialize(view)
@columns = Array.new
@view = view
end
def add_column(options, block)
columns << TableBuilderHelper::TableColumn.new(options.merge(:unordered => @columns.length), block, @view)
end
def set_row_dom_id_method(block)
@row_dom_id = block
end
###################
# #
# Builder Methods #
# #
###################
def header_row(html, page_requester)
html.tr do
columns.each do |column|
column.header_cell(html, page_requester)
end
end
end
def content_row(html, item)
row_options = @row_dom_id ? { :id => @row_dom_id[item] } : {}
html.tr row_options do
columns.each { |column| column.content_cell(html, item) }
end
end
def generate(contents, page_requester)
columns.sort!
html = Builder::XmlMarkup.new(:indent => 4, :target => Array.new)
html.table do
header_row(html, page_requester)
contents.each { |item| content_row(html, item) }
end
html.target!.join
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment