# A simple HTML table with three columns: label, contents, and (optionally) note. # Each row is called a field. # The last row can optionally contain "buttons" (actually any widget will do) # that are all shown in the 2nd column. # It's all surrounded with a fieldset element for a title. # # In ASCII art, it looks something like this: # # /-Meals----------------------------------------\ # | Breakfast | eggs | | # | Lunch | sandwich | | # | Dinner | lo mein | with shrimp! | # | | [Save] [Cancel] | | # \----------------------------------------------/ # # There are two ways to create a FieldTable. # 1. Pass a block in to the constructor. # 2. Make a subclass. # In both cases you'll want to call the "field" and "button" methods on the table. # This sets up the contents which will be rendered later during FieldTable#content. # If you make a subclass (#2) you can do this either in the constructor or in # the content method *before* you call super. # # The FieldTable is surrounded by a fieldset element whose legend is the "title" instance variable. # Inside this fieldset is a table element. # Each field (row of the table) has a label (th), a content cell (td), and an optional note (td). # # If you call "button" you can pass in a block that'll get rendered inside the 2nd column of the last row. The idea here is that you might want to make an HTML form that has a bunch of buttons at the bottom (Save, Cancel, Clear) and these all go in the same cell, with no label for the row. # # TODO: error messages? # @author Alex Chaffee class FieldTable < Erector::Widget include Erector::Inline class Field < Erector::Widget needs :label, :note => nil def content tr :class => "field_table_field" do th do text @label text ":" unless @label.nil? end td do super # calls the block end if @note td do text @note end end end end end # Define a field, containing a label, optional note, and block for the contents # # TODO: allow passing in a widget instead of a block def field(label = nil, note = nil, &contents) @fields << Field.new(:label => label, :note => note, &contents) end # If you call "button" you can pass in a block that'll get rendered inside the 2nd column of the # last row. The idea here is that you might want to make an HTML form that has a bunch of buttons at # the bottom (Save, Cancel, Clear) and these all go in the same cell, with no label for the row. # # TODO: allow passing in a widget instead of a block def button(&button_proc) @buttons << button_proc end needs :title # Pass in a block and it'll get called with a pointer to this table, so you can call # 'field' and 'button' to configure it def initialize(*args) super @fields = [] @buttons = [] yield self if block_given? # invoke the configuration block end def content fieldset :class => "field_table" do legend @title table :width => '100%' do @fields.each do |f| widget f end unless @buttons.empty? tr :class => "field_table_buttons" do td :colspan => 2, :align => "right" do table :class => 'layout' do tr do @buttons.each do |button| td :class => "field_table_button" do button.call end end end end end end end end end end end