root/lib/html_builder/stacking_table.rb @ fc30c2a2
b689e231 | Marc Dequènes (Duck) | #!/usr/bin/ruby
|
|
class HtmlBuilder::StackingTable
|
|||
attr_accessor :inner_table
|
|||
def initialize(caption = nil, html_options = {})
|
|||
@caption = caption
|
|||
@html_options = html_options
|
|||
@inner_table = false
|
|||
end
|
|||
def build
|
|||
options = ""
|
|||
@html_options.each_pair {|opt, val| options += " #{opt}=\"#{val}\"" }
|
|||
html = "<table#{options}>\n"
|
|||
t = create_table()
|
|||
t.inner_table = @inner_table
|
|||
yield(t)
|
|||
t.calculate_depths
|
|||
t.propagate_parameters
|
|||
html += t.build
|
|||
html += "</table>\n"
|
|||
return html
|
|||
end
|
|||
def create_table
|
|||
Table.new(@caption)
|
|||
end
|
|||
class Container
|
|||
def initialize(name)
|
|||
@name = name
|
|||
@elements = []
|
|||
@x_depth = 0
|
|||
@y_depth = 0
|
|||
@fill_x_depth = nil
|
|||
end
|
|||
def content(text, html_options = {})
|
|||
text = [text] unless text.kind_of? Array
|
|||
if html_options.empty?
|
|||
@elements << text
|
|||
else
|
|||
options = ""
|
|||
html_options.each_pair {|opt, val| options += " #{opt}=\"#{val}\"" }
|
|||
prepared_text = text.collect {|t| "<span#{options}>#{t}</span>" }
|
|||
@elements << prepared_text
|
|||
end
|
|||
end
|
|||
def category(cat_name)
|
|||
c = create_category(cat_name)
|
|||
yield(c)
|
|||
@elements << c
|
|||
end
|
|||
def calculate_depths
|
|||
y_depth = 0
|
|||
@elements.each do |el|
|
|||
if el.respond_to? :build
|
|||
e_x_depth, e_y_depth = el.calculate_depths
|
|||
x_depth = e_x_depth + 1
|
|||
y_depth += e_y_depth
|
|||
elsif el.kind_of? Array
|
|||
x_depth = el.size
|
|||
y_depth += 1
|
|||
else
|
|||
x_depth = 1
|
|||
y_depth += 1
|
|||
end
|
|||
@x_depth = x_depth if x_depth > @x_depth
|
|||
@y_depth = y_depth
|
|||
end
|
|||
# in case category is empty
|
|||
@y_depth = [1, @y_depth].max
|
|||
return @x_depth, @y_depth
|
|||
end
|
|||
def propagate_parameters(depth = nil)
|
|||
if depth.nil?
|
|||
depth = @x_depth
|
|||
else
|
|||
depth -= 1
|
|||
end
|
|||
@fill_x_depth = depth
|
|||
@elements.each do |el|
|
|||
el.propagate_parameters(depth) if el.respond_to? :build
|
|||
end
|
|||
end
|
|||
def build
|
|||
lines = fetch_lines()
|
|||
options = (@y_depth > 1) ? " rowspan=\"#{@y_depth}\"" : ""
|
|||
lines << [] if lines.empty?
|
|||
lines.first.unshift "<th#{options}>#{@name}</th>"
|
|||
return lines
|
|||
end
|
|||
private
|
|||
def create_category(cat_name)
|
|||
Category.new(cat_name)
|
|||
end
|
|||
def fetch_lines
|
|||
lines = []
|
|||
@elements.each do |el|
|
|||
if el.respond_to? :build
|
|||
lines += el.build
|
|||
elsif el.kind_of? Array
|
|||
l = ""
|
|||
last_el = el.pop
|
|||
x_depth_left = @fill_x_depth - el.size
|
|||
first_el = el.shift
|
|||
tag = ((self.kind_of?(Table) and not @inner_table) ? "th" : "td")
|
|||
l += "<#{tag}>#{first_el}</#{tag}>" unless first_el.nil?
|
|||
el.each {|s_el| l += "<td>#{s_el}</td>"}
|
|||
options = (x_depth_left > 1) ? " colspan=\"#{x_depth_left}\"" : ""
|
|||
l += "<td#{options}>#{last_el}</td>" unless last_el.nil?
|
|||
lines << [ l ]
|
|||
else
|
|||
options = (@x_depth > 1) ? " colspan=\"#{@x_depth}\"" : ""
|
|||
lines << [ "<td#{options}>#{el}</td>" ]
|
|||
end
|
|||
end
|
|||
return lines
|
|||
end
|
|||
end
|
|||
class Category < Container
|
|||
end
|
|||
class Table < Container
|
|||
attr_accessor :inner_table
|
|||
def initialize(name = nil)
|
|||
super
|
|||
@inner_table = false
|
|||
end
|
|||
def build
|
|||
html = ""
|
|||
html += "<caption>#{@name}</caption>\n" if @name
|
|||
lines = fetch_lines()
|
|||
lines.each {|l| html += "<tr>#{l}</tr>\n"}
|
|||
return html
|
|||
end
|
|||
end
|
|||
end
|
|||
# example
|
|||
if $0 == __FILE__
|
|||
h = {"z" => "PLOP", "coin" => {"toto" => "erb", "titi" => {"gtk" => "gh"}}}
|
|||
z = StackingTable.build("Super Caption !!!") do |table|
|
|||
table.content("coucou")
|
|||
table.category("Cat 1") do |cat|
|
|||
cat.content("plop")
|
|||
cat.content("toto")
|
|||
cat.category("Cat 2") do |cat|
|
|||
cat.content("titi")
|
|||
end
|
|||
end
|
|||
end
|
|||
puts z
|
|||
end
|