Source code for uw.web.html.format
"""Miscellaneous HTML formatting routines.
Routines for formatting various objects as HTML, a convenience
routine for slightly simplifying the provision of manually-generated
"breadcrumb" links, and a routine for formatting simple HTML tables.
"""
import datetime
from ll.xist.ns import html
from uw.web.html.join import html_join
[docs]def format (item):
"""Format an item as HTML.
:param item: a value to format as HTML in a reasonable default way.
If the input is None, the output is None. If the input is a datetime
type, the .isoformat() method is used. Otherwise, the item is converted
to a string using str().
"""
if item is None:
return None
if isinstance (item, datetime.date) or isinstance (item, datetime.time) \
or isinstance (item, datetime.datetime):
return item.isoformat ()
return str (item)
[docs]def format_date (date, none=None):
"""Format a date in the standard ISO 8601 form.
:param date: The date to format (datetime.date) or None.
:param none: The value to use if the input is None.
Formats the date in the standard ISO 8601 format. If the input is None
or the maximum date or datetime, the output is the specified alternate
value or None.
"""
if date in [None, datetime.datetime.max, datetime.date.max]:
return none
return date.strftime ('%Y-%m-%d')
[docs]def format_time (time, none=None):
"""Format a time in the standard ISO 8601 form.
:param time: The date to format (datetime.time) or None.
:param none: The value to use if the input is None.
Formats the time in the standard ISO 8601 format. If the input is None,
the output is the specified alternate value or None.
"""
if time in [None]:
return none
return time.strftime ('%H:%M')
[docs]def format_datetime (time, none=None):
"""Format a datetime in the standard ISO 8601 form.
:param time: The datetime to format (datetime.datetime) or None.
:param none: The value to use if the input is None.
Formats the datetime in the standard ISO 8601 format, to the minute.
If the input is None or the maximum datetime, the output is the specified
alternate value or None.
"""
if time in [None, datetime.datetime.max]:
return none
return time.strftime ('%Y-%m-%d %H:%M')
[docs]def format_email (email):
"""Format an email address as HTML.
:param email: an email address.
Returns a mailto link for the specified email address.
"""
if email is None:
return None
return html.a (html.tt (email), href="mailto:%s" % email)
[docs]def format_return (*names, **keys):
"""Return HTML formatting of "breadcrumbs".
:param \*names: the short titles to use for href="..", href="../..", etc.
:param keys['dot']: the short title to use for href=".".
Returns an HTML <p> with relative links to parent directories corresponding
to the parameter names provided, and possibly an additional link to the
current directory if a "dot" keyword argument is provided. The link text
is the provided names. If a provided name is None, the corresponding link
is skipped.
This is a way of making it easy to jump back from a detailed page to a
higher level of the application. Unfortunately higher levels of the
navigation tend to get repeated everywhere.
**TODO: implement real breadcrumbs integrated with a menu system and with
page titles.**
"""
length = len (names)
result = [None] * length
for i, name in enumerate (names):
if name is not None:
result[i] = html.a (name, href='/'.join ([".."] * (length - i)))
if 'dot' in keys:
result.append (html.a (keys['dot'], href="."))
return html.p ('Return to ', html_join (result, ', '))
[docs]def make_table_format (*columns, **keys):
"""Compute a function for producing an HTML <table>.
:param columns: a list of column definitions.
:param keys['header_row']: a function to be invoked before the first item
row which may also return an extra row.
:param keys['before_row']: a function to be invoked before each item row
which may also return an extra row.
:param keys['after_row']: a function to be invoked after each item row
which may also return an extra row.
:param keys['footer_row']: a function to be invoked after the last item row
which may also return an extra row.
:param keys['row_attributor']: a function to be invoked on each item which
returns a dictionary of attributes for the <tr> element.
:param keys['use_colgroup']: whether or not to include an HTML <colgroup>
element at the beginning of the table.
Returns a function which, when passed a list of items, returns an HTML
<table> with one column for each entry in columns, and one row for each
item in the list of items, as well as a header row and possibly some
additional rows depending on the optional keyword parameters supplied.
Each element of columns is a column definition, which is a 4-tuple
consisting of:
- an HTML <col> element for the column;
- the HTML contents of the header for the column;
- a function which takes an item and returns HTML for the column;
- a function which takes an item and returns HTML attributes for the <td>
element.
The later elements of the tuple may be omitted in which case appropriate
neutral values will be used. The <col> element may also be omitted; this
case is recognized when the first element of the tuple is not an
ll.xist.ns.html.col object.
The \*_row keyword parameters specify additional computations to take place
at the noted point in computation of the result table. They may also
return additional rows if that is useful in a particular use. One use of
this is for header_row to initialize counters or totals, and footer_row
to produce a row which displays the final results.
"""
colgroup = []
headings = []
formatters = []
for column in columns:
column = list (column)
if len (column) < 1 or type (column[0]) is not html.col:
column.insert (0, html.col ())
if len (column) < 2:
column.append (None)
if len (column) < 3:
column.append (lambda r: None)
if len (column) < 4:
column.append (lambda r: {})
col, heading, formatter, attributor = column
colgroup.append (col)
headings.append (heading)
formatters.append ((formatter, attributor))
headings = tuple (headings)
formatters = tuple (formatters)
header_row = keys.get ('header_row')
before_row = keys.get ('before_row')
after_row = keys.get ('after_row')
footer_row = keys.get ('footer_row')
row_attributor = keys.get ('row_attributor', lambda r: {})
use_colgroup = keys.get ('use_colgroup')
def format_table (rows):
result = html.table (
html.colgroup (col for col in colgroup) if use_colgroup else None,
html.tr (html.th (heading) for heading in headings),
)
if header_row is not None:
result.append (header_row ())
for row in rows:
if before_row is not None:
result.append (before_row (row))
result.append (html.tr (
[html.td (formatter (row), **attributor (row)) for formatter, attributor in formatters],
**row_attributor (row)
))
if after_row is not None:
result.append (after_row (row))
if footer_row is not None:
result.append (footer_row ())
return result
return format_table