1+ object TABLE
2+ name: "Table Content Flyweight Delegate"
3+ parent: ROOT
4+ location: FIRST_ROOM
5+ owner: HACKER
6+ readable: true
7+
8+ verb mk (this none this) owner: HACKER flags: "rxd"
9+ "Create table flyweight with headers and rows";
10+ {headers, rows} = args;
11+ typeof(headers) != LIST && raise(E_TYPE, "Headers must be a list");
12+ typeof(rows) != LIST && raise(E_TYPE, "Rows must be a list");
13+ return <this, [headers -> headers, rows -> rows]>;
14+ endverb
15+
16+ verb compose (this none this) owner: HACKER flags: "rxd"
17+ "Compose table content into appropriate format";
18+ {render_for, content_type, event} = args;
19+ headers = this.headers;
20+ rows = this.rows;
21+ if (!headers || !rows)
22+ if (content_type == 'text_html)
23+ return <$html, {"p", {}, {"(empty table)"}}>;
24+ else
25+ return "(empty table)";
26+ endif
27+ endif
28+ if (content_type == 'text_html)
29+ "Build HTML table structure";
30+ table_children = {};
31+ "Add header row if present";
32+ if (headers)
33+ header_cells = {};
34+ for header in (headers)
35+ if (typeof(header) == STR)
36+ header_content = header;
37+ elseif (typeof(header) == FLYWEIGHT)
38+ header_content = header:compose(@args);
39+ else
40+ header_content = tostr(header);
41+ endif
42+ header_cells = {@header_cells, <$html, {"th", {}, {header_content}}>};
43+ endfor
44+ thead = <$html, {"thead", {}, {<$html, {"tr", {}, header_cells}>}}>;
45+ table_children = {@table_children, thead};
46+ endif
47+ "Add body rows";
48+ body_rows = {};
49+ for row in (rows)
50+ row_cells = {};
51+ for cell in (row)
52+ if (typeof(cell) == STR)
53+ cell_content = cell;
54+ elseif (typeof(cell) == FLYWEIGHT)
55+ cell_content = cell:compose(@args);
56+ else
57+ cell_content = tostr(cell);
58+ endif
59+ row_cells = {@row_cells, <$html, {"td", {}, {cell_content}}>};
60+ endfor
61+ body_rows = {@body_rows, <$html, {"tr", {}, row_cells}>};
62+ endfor
63+ tbody = <$html, {"tbody", {}, body_rows}>;
64+ table_children = {@table_children, tbody};
65+ return <$html, {"table", {}, table_children}>;
66+ else
67+ "Plain text table output";
68+ result = {};
69+ "Calculate column widths";
70+ widths = {};
71+ for i in [1..length(headers)]
72+ widths = {@widths, length(tostr(headers[i]))};
73+ endfor
74+ for row in (rows)
75+ for i in [1..min(length(row), length(widths))]
76+ cell_width = length(tostr(row[i]));
77+ if (cell_width > widths[i])
78+ widths[i] = cell_width;
79+ endif
80+ endfor
81+ endfor
82+ "Build header line";
83+ line = "";
84+ for i in [1..length(headers)]
85+ if (i > 1)
86+ line = line + " | ";
87+ endif
88+ line = line + $str_proto:pad_right(tostr(headers[i]), widths[i]);
89+ endfor
90+ result = {@result, line};
91+ "Build separator";
92+ line = "";
93+ for i in [1..length(headers)]
94+ if (i > 1)
95+ line = line + "-+-";
96+ endif
97+ line = line + $str_proto:space(widths[i], "-");
98+ endfor
99+ result = {@result, line};
100+ "Build data rows";
101+ for row in (rows)
102+ line = "";
103+ for i in [1..length(headers)]
104+ if (i > 1)
105+ line = line + " | ";
106+ endif
107+ cell = i <= length(row) ? tostr(row[i]) | "";
108+ line = line + $str_proto:pad_right(cell, widths[i]);
109+ endfor
110+ result = {@result, line};
111+ endfor
112+ return result:join("\n");
113+ endif
114+ endverb
115+
116+ verb test_simple_table (this none this) owner: HACKER flags: "rxd"
117+ "Test creating simple HTML table";
118+ headers = {"Name", "Age"};
119+ rows = {{"Alice", "25"}, {"Bob", "30"}};
120+ table_obj = this:mk(headers, rows);
121+ html_result = table_obj:compose($nothing, 'text_html, $nothing);
122+ xml_result = html_result:render('text_html);
123+ parsed = xml_parse(xml_result, LIST);
124+ "Verify basic table structure";
125+ parsed[1] != "table" && return E_ASSERT;
126+ "Should have thead and tbody";
127+ length(parsed) < 3 && raise(E_INVARG, "parsed structure: " + toliteral(parsed));
128+ return true;
129+ endverb
130+
131+ verb test_plain_text_table (this none this) owner: HACKER flags: "rxd"
132+ "Test plain text table output";
133+ headers = {"Item", "Price"};
134+ rows = {{"Apple", "$1.00"}, {"Banana", "$0.50"}};
135+ table_obj = this:mk(headers, rows);
136+ text_result = table_obj:compose($nothing, 'text_plain, $nothing);
137+ "Should contain headers and separator";
138+ !index(text_result, "Item") || !index(text_result, "Price") || !index(text_result, "---") && raise(E_INVARG, "text result: " + toliteral(text_result));
139+ return true;
140+ endverb
141+ endobject
0 commit comments