David Spickett | 82c94b2 | 2023-06-12 16:18:33 +0100 | [diff] [blame] | 1 | # This file contains a basic "builder" style API for making HTML tables |
| 2 | # and writing them to a file once finished. |
| 3 | # |
| 4 | # Use it as follows: |
| 5 | # with Table(outfile) as table: |
| 6 | # table.AddRow().AddCell("foo") |
| 7 | # |
| 8 | # To get: |
| 9 | # <table> |
| 10 | # <td>foo</td> |
| 11 | # </table> |
| 12 | # |
| 13 | # Methods return a reference to self, or to the new thing you added. |
| 14 | # This means you can keep chaining calls to build what you want. |
| 15 | # |
| 16 | # table.AddRow().AddCell("foo").Colspan(1).Style("mystyle") |
| 17 | |
| 18 | |
| 19 | class TableCell(object): |
| 20 | def __init__(self, name, content=None): |
| 21 | self.name = name |
| 22 | self.content = content |
| 23 | self.style = None |
| 24 | self.colspan = None |
| 25 | |
| 26 | def Style(self, style): |
| 27 | self.style = style |
| 28 | return self |
| 29 | |
| 30 | def Colspan(self, colspan): |
| 31 | self.colspan = colspan |
| 32 | return self |
| 33 | |
| 34 | def Content(self, content): |
| 35 | self.content = content |
| 36 | return self |
| 37 | |
| 38 | def __str__(self): |
| 39 | return " <{}{}{}>{}</{}>".format( |
| 40 | self.name, |
| 41 | "" if self.style is None else ' style="{}"'.format(self.style), |
| 42 | "" if self.colspan is None else " colspan={}".format(self.colspan), |
| 43 | " " if self.content is None else self.content, |
| 44 | self.name, |
| 45 | ) |
| 46 | |
| 47 | |
| 48 | class Cell(TableCell): |
| 49 | def __init__(self, content=None): |
| 50 | super(Cell, self).__init__("td", content) |
| 51 | |
| 52 | |
| 53 | class Header(TableCell): |
| 54 | def __init__(self, content=None): |
| 55 | super(Header, self).__init__("th", content) |
| 56 | |
| 57 | |
| 58 | class Row(object): |
| 59 | def __init__(self): |
| 60 | self.cells = [] |
| 61 | |
| 62 | def AddCell(self, content=None): |
| 63 | self.cells.append(Cell(content)) |
| 64 | return self.cells[-1] |
| 65 | |
| 66 | def AddHeader(self, content=None): |
| 67 | self.cells.append(Header(content)) |
| 68 | return self.cells[-1] |
| 69 | |
| 70 | def __str__(self): |
| 71 | return "\n".join([" <tr>", *map(str, self.cells), " </tr>"]) |
| 72 | |
| 73 | |
| 74 | class TableBody(object): |
| 75 | def __init__(self, close=False): |
| 76 | self.close = close |
| 77 | |
| 78 | def __str__(self): |
| 79 | return "<{}tbody>".format("/" if self.close else "") |
| 80 | |
| 81 | |
| 82 | class Table(object): |
| 83 | def __init__(self, out): |
| 84 | self.out = out |
| 85 | self.rows = [] |
| 86 | self.border = None |
| 87 | self.cellspacing = None |
| 88 | self.cellpadding = None |
| 89 | self.body_begins = None |
| 90 | |
| 91 | def __enter__(self): |
| 92 | return self |
| 93 | |
| 94 | def __exit__(self, *args): |
| 95 | self.out.write("\n" + str(self)) |
| 96 | |
| 97 | def __str__(self): |
| 98 | open_tag = "<table{}{}{}>".format( |
| 99 | "" if self.border is None else " border={}".format(self.border), |
| 100 | "" |
| 101 | if self.cellspacing is None |
| 102 | else " cellspacing={}".format(self.cellspacing), |
| 103 | "" |
| 104 | if self.cellpadding is None |
| 105 | else " cellpadding={}".format(self.cellpadding), |
| 106 | ) |
| 107 | rows = map(str, self.rows) |
| 108 | close_tag = "</table>" |
| 109 | |
| 110 | return "\n".join([open_tag, *rows, close_tag]) |
| 111 | |
| 112 | def AddRow(self): |
| 113 | self.rows.append(Row()) |
| 114 | return self.rows[-1] |
| 115 | |
| 116 | def Border(self, border): |
| 117 | self.border = border |
| 118 | return self |
| 119 | |
| 120 | def Cellspacing(self, cellspacing): |
| 121 | self.cellspacing = cellspacing |
| 122 | return self |
| 123 | |
| 124 | def Cellpadding(self, cellpadding): |
| 125 | self.cellpadding = cellpadding |
| 126 | return self |
| 127 | |
| 128 | def BeginBody(self): |
| 129 | self.rows.append(TableBody()) |
| 130 | |
| 131 | def EndBody(self): |
| 132 | self.rows.append(TableBody(close=True)) |