Project

General

Profile

Download (3.69 KB) Statistics
| Branch: | Tag: | Revision:
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