'
table = htmltag('table', border=2) # Does the same thing.
# You can also override tr, td and th. (Their end-tag counterarts are
# ntable, ntr, ntd and nth, but there's no reason to override those.)
html = MyTable.build(data, headers)
If you have more complex needs you can build the table manually:
t = table.Table()
ths = [t.th] * len(headers)
t.row(headers, ths)
for row in data:
t.row(row)
html = t.finish()
The second argument to .row() is a list of '' or ' | ' tags to apply, one
for each cell in the row. The default is '[self.td] * len(row)'. You'll
have to supply your own list if you want any ' | 's, or if you want to use
different ' | ' styles for different cells. (Actually, there is a method
.headers_row that behaves like .row but uses ' | '.)
One use for this flexibility is to insert periodic "group header" rows that
span all columns:
td_colspan = ' | '
t.row(["Group Header Text"], [td_colspan])
Table is a subclass of PlainTable, which has completely unadorned tags
(e.g., ''). PlainTable is useful for subclassing but not very useful as
is, since an unadorned table has no gridlines.
HorizontalTable applies a special '' style to the first column, useful when
you want the headers on the left rather than the top.
data = [('Flintstone', 'Fred', 'Wilma'), ('Rubble', 'Barney', 'Betty')]
html = HorizontalTable.build(data)
The left column is right-justified by default. You can specify otherwise via
the .th_first_column attribute.
You can have headers both on the left and on the top by adding the 'headers'
argument:
headers = (None, 'Husband', 'Wife')
html = HorizontalTable.build(data, headers)
The top-left cell is formatted as a header-row cell, not as a left-column cell.
Normally you'll just want it blank.
This class (only) has a method to display a mapping as a table:
html = HorizontalTable.build_from_dict(os.environ)
The keys are rendered in alphabetical order.
ReportTable is like HorizontalTable without gridlines. It's useful for
presenting two-column data in a way that doesn't look like a table, such as the
details of a database record.
SortedTable is a standard (vertical) table with one column in a special style.
By convention this indicates the data is sorted by that column, and the other column
headers are hyperlinks to re-sort the data by that column. This build method
takes three arguments:
html = SortedTable.build(data, headers, 2)
The first column is zero, so this highlights the third column. The style is
determined by the .key_th and .key_td attributes; the default ' | ' has a
light green background and the default ' | ' is normal. Note how easy it is
to structure your calling code:
- Assume a certain column by default, say the first.
- The first column's header is plain text.
- The other columns' headers are hyperlinks like "page?sort=2", where
'page' is the relative URL and '2' is the column number to sort by.
- The table renders with the first column highlighted.
- The user clicks on the third column (the one numbered 2).
- Your program finds a GET parameter of '2', converts it to an integer,
sorts by that field, and passes it as the third argument to
SortedTable.build().
- The table renders with the third column highlighted....
PlainTable.columnize(list_, delim=BR) converts a list (each column) of lists
(the items in the column) to a one-row table. Each cell contains the items
concatenated with 'delim' in between. This method is inherited by all the
other classes, although since it depends on .build() it'll fail for classes
like SortedTable where the .build() signature is different.
This module depends on Quixote
(http://www.mems-exchange.org/software/quixote/)
but uses only its utility functions, not its publishing loop.
It has been tested with Quixote 2.0a4, but not with Quixote 1.x.
Author: Mike Orr
"""
from quixote.html import TemplateIO, htmlescape, htmltag, htmltext
# Returned by the .build() methods if a table has no rows.
_nulltable = htmltag('')
NBSP = htmltext(' ')
BR = htmltag('br', True) + '\n'
class PlainTable(object):
"""Build an HTML table.
The default tag style is a plain table with no gridlines. You can
override the tags if you want something fancier.
"""
table = htmltag('table')
ntable = htmltag('/table')
tr = htmltag('tr')
ntr = htmltag('/tr')
td = htmltag('td')
ntd = htmltag('/td')
th = htmltag('th')
nth = htmltag('/th')
def __init__(self):
self.sio = TemplateIO(html=True)
self.has_rows = False
def row(self, row, tds=None):
self.has_rows = True
cols = len(row)
if tds is None:
tds = self.make_tds(row)
elif len(tds) != cols:
raise ValueError("args 'row' and 'tds' are different lengths")
ntds = self.make_ntds(tds)
self.sio += self.tr
self.sio += '\n'
for cell, td, ntd in zip(row, tds, ntds):
self.sio += td
if cell is None or cell == '':
self.sio += NBSP
else:
self.sio += cell
self.sio += ntd
self.sio += '\n'
self.sio += self.ntr
self.sio += '\n'
def headers_row(self, row):
tds = self.make_tds_first_row(row)
self.row(row, tds)
def finish(self):
tup = self.table, self.sio.getvalue(), self.ntable
return htmltext("%s\n%s%s\n\n") % tup
getvalue = finish
def make_tds(self, row):
return [self.td] * len(row)
def make_tds_first_row(self, row):
return [self.th] * len(row)
def make_ntds(self, row):
return [x.lower().startswith(' | | |